mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-08 00:50:28 +08:00
Compare commits
177 Commits
Author | SHA1 | Date | |
---|---|---|---|
3354945119 | |||
19c4416f10 | |||
2077db9091 | |||
800f0ed249 | |||
6161040c67 | |||
1d785e61c6 | |||
0329d24867 | |||
fb6f3623ee | |||
eb448bd043 | |||
ea88839db9 | |||
cb95f6977a | |||
9067df92a7 | |||
bfa2ab63ad | |||
505054b0eb | |||
f95ce13b82 | |||
5315f16a48 | |||
d054f3e001 | |||
b158b840bd | |||
b16f1807b3 | |||
d0cce1bf7a | |||
9892cd20ab | |||
d1f31dd327 | |||
94743246a1 | |||
39ad1bc593 | |||
d97f833d2a | |||
948fa911e2 | |||
6073a0f63d | |||
91268bca70 | |||
23dbb0b926 | |||
97cc1f9e2b | |||
8c415be7c7 | |||
e87165cfc8 | |||
fc4fa2e8b6 | |||
44ae76503e | |||
ae1634a4d5 | |||
bdf9864f69 | |||
72839d6bf5 | |||
2c4b1093ed | |||
d1c55d5aa7 | |||
c8aa35c9c6 | |||
6037f37b87 | |||
1b478903d8 | |||
4f5ac7a10b | |||
e81ba62234 | |||
a19060c7cb | |||
96812f676b | |||
04f0458b5c | |||
fd0bcd9a17 | |||
01a5958307 | |||
be88b00278 | |||
1bd0245e7a | |||
cc84bd37cf | |||
8302fcf805 | |||
391a533ce1 | |||
57431a59ad | |||
88a4736520 | |||
2cb6ff69ae | |||
e1e5943a3e | |||
3875896c1e | |||
7e2f265420 | |||
53ef179e9b | |||
376ef0ed14 | |||
ca183be336 | |||
e5da57a005 | |||
e4e225db32 | |||
a1add992ee | |||
2aac265ed4 | |||
2dc755f529 | |||
0dd474d5fc | |||
6998451e97 | |||
9175e5b664 | |||
dbc6b0dc45 | |||
31b7000f6a | |||
d25eaa65cd | |||
f5bcd00652 | |||
0d5f49e40a | |||
3527e070a0 | |||
0108b58db4 | |||
976b5766a5 | |||
a92d20162a | |||
204b1c2b8c | |||
49fb269170 | |||
c532a5d54d | |||
89df80baca | |||
d988ac814c | |||
e4b25055d5 | |||
4123d47174 | |||
fbdd5a926d | |||
92b6fda0f6 | |||
6a7ac35e65 | |||
fc137b9f76 | |||
11dbd5ba9a | |||
19942a8bd4 | |||
f9ee8a68cb | |||
f241336ad7 | |||
8b64d113fb | |||
a8800c4d5c | |||
75fc9ab9f7 | |||
d06da76c3d | |||
bc399837cc | |||
265abfe102 | |||
12acb24dbc | |||
ba1ddc7e50 | |||
59e07a35aa | |||
cabe830f55 | |||
78af5daec3 | |||
6c76913f71 | |||
5a0d1bcb6e | |||
37232faa07 | |||
4d9c81ef96 | |||
b0d87f60ae | |||
a5499219d1 | |||
6a813a1f8c | |||
e4cf244cf8 | |||
f5a6415e57 | |||
13e871043c | |||
a8699d0b87 | |||
6621d693de | |||
dc3131c683 | |||
042a8d0ad6 | |||
44abfb3430 | |||
53b8424a1f | |||
23c2ba3a2b | |||
3a9ffedce4 | |||
03f005389f | |||
69a8346d05 | |||
546512a0ea | |||
c4a307b9ec | |||
d731c3c934 | |||
4a68dd65cd | |||
d59148890e | |||
7f52755e32 | |||
eaa6f50085 | |||
f35a5f9a47 | |||
7481b229a4 | |||
39e485ae82 | |||
764c64e67c | |||
e755a7331d | |||
6d9d595f86 | |||
d52058d2ae | |||
bcfbfc6947 | |||
75699c4a26 | |||
3e8bfb52a8 | |||
bbbd857a45 | |||
498900df76 | |||
7e3c1a6581 | |||
6e28043dba | |||
cb200687dc | |||
23bb0ee450 | |||
117259dfc5 | |||
e71d0476f0 | |||
b5d26767b2 | |||
5c4e22288e | |||
3ac4be64b8 | |||
97db54b6b9 | |||
3a19d4c7c8 | |||
a60be2b2ab | |||
06ef97a080 | |||
167c1b0f1b | |||
7d0eae230e | |||
901867e8bb | |||
b7be1943fa | |||
bbbda1982f | |||
e593f5be5b | |||
0918757e85 | |||
ce0d45a70b | |||
c4096788b2 | |||
523186f895 | |||
ef373ca736 | |||
721a681ff1 | |||
8b1c4b0c75 | |||
540f22f8bd | |||
79f81f1356 | |||
4e145f71b5 | |||
104f975a2f | |||
71bb400559 | |||
93c3c78d42 |
9
.github/workflows/build.yml
vendored
9
.github/workflows/build.yml
vendored
@ -108,6 +108,7 @@ jobs:
|
||||
working-directory: ./web
|
||||
- uses: cypress-io/github-action@v5
|
||||
with:
|
||||
browser: chrome
|
||||
start: yarn start
|
||||
wait-on: 'http://localhost:7001'
|
||||
wait-on-timeout: 210
|
||||
@ -127,7 +128,7 @@ jobs:
|
||||
release-and-push:
|
||||
name: Release And Push
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'casbin/casdoor' && github.event_name == 'push'
|
||||
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push'
|
||||
needs: [ frontend, backend, linter, e2e ]
|
||||
steps:
|
||||
- name: Checkout
|
||||
@ -182,14 +183,14 @@ jobs:
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
if: github.repository == 'casbin/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
|
||||
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- name: Push to Docker Hub
|
||||
uses: docker/build-push-action@v3
|
||||
if: github.repository == 'casbin/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
|
||||
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
|
||||
with:
|
||||
context: .
|
||||
target: STANDARD
|
||||
@ -199,7 +200,7 @@ jobs:
|
||||
|
||||
- name: Push All In One Version to Docker Hub
|
||||
uses: docker/build-push-action@v3
|
||||
if: github.repository == 'casbin/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
|
||||
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
|
||||
with:
|
||||
context: .
|
||||
target: ALLINONE
|
||||
|
2
.github/workflows/sync.yml
vendored
2
.github/workflows/sync.yml
vendored
@ -7,7 +7,7 @@ on:
|
||||
jobs:
|
||||
synchronize-with-crowdin:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'casbin/casdoor' && github.event_name == 'push'
|
||||
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push'
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
|
@ -16,6 +16,7 @@ ARG USER=casdoor
|
||||
|
||||
RUN sed -i 's/https/http/' /etc/apk/repositories
|
||||
RUN apk add --update sudo
|
||||
RUN apk add tzdata
|
||||
RUN apk add curl
|
||||
RUN apk add ca-certificates && update-ca-certificates
|
||||
|
||||
|
@ -87,8 +87,7 @@ https://casdoor.org/docs/category/integrations
|
||||
## How to contact?
|
||||
|
||||
- Discord: https://discord.gg/5rPsrAzK7S
|
||||
- Forum: https://forum.casbin.com
|
||||
- Contact: https://tawk.to/chat/623352fea34c2456412b8c51/1fuc7od6e
|
||||
- Contact: https://casdoor.org/help
|
||||
|
||||
## Contribute
|
||||
|
||||
|
@ -51,7 +51,8 @@ p, *, *, GET, /api/get-account, *, *
|
||||
p, *, *, GET, /api/userinfo, *, *
|
||||
p, *, *, GET, /api/user, *, *
|
||||
p, *, *, GET, /api/health, *, *
|
||||
p, *, *, POST, /api/webhook, *, *
|
||||
p, *, *, *, /api/webhook, *, *
|
||||
p, *, *, GET, /api/get-qrcode, *, *
|
||||
p, *, *, GET, /api/get-webhook-event, *, *
|
||||
p, *, *, GET, /api/get-captcha-status, *, *
|
||||
p, *, *, *, /api/login/oauth, *, *
|
||||
@ -80,6 +81,7 @@ p, *, *, *, /.well-known/jwks, *, *
|
||||
p, *, *, GET, /api/get-saml-login, *, *
|
||||
p, *, *, POST, /api/acs, *, *
|
||||
p, *, *, GET, /api/saml/metadata, *, *
|
||||
p, *, *, *, /api/saml/redirect, *, *
|
||||
p, *, *, *, /cas, *, *
|
||||
p, *, *, *, /scim, *, *
|
||||
p, *, *, *, /api/webauthn, *, *
|
||||
@ -95,6 +97,8 @@ p, *, *, GET, /api/get-organization-names, *, *
|
||||
p, *, *, GET, /api/get-all-objects, *, *
|
||||
p, *, *, GET, /api/get-all-actions, *, *
|
||||
p, *, *, GET, /api/get-all-roles, *, *
|
||||
p, *, *, GET, /api/get-invitation-info, *, *
|
||||
p, *, *, GET, /api/faceid-signin-begin, *, *
|
||||
`
|
||||
|
||||
sa := stringadapter.NewAdapter(ruleText)
|
||||
@ -150,7 +154,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 {
|
||||
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/") {
|
||||
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
|
||||
} else if urlPath == "/api/update-user" {
|
||||
// Allow ordinary users to update their own information
|
||||
@ -158,6 +162,11 @@ func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} else if urlPath == "/api/upload-resource" {
|
||||
if subOwner == "app" && subName == "app-casibase" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ socks5Proxy = "127.0.0.1:10808"
|
||||
verificationCodeTimeout = 10
|
||||
initScore = 0
|
||||
logPostOnly = true
|
||||
isUsernameLowered = false
|
||||
origin =
|
||||
originFrontend =
|
||||
staticBaseUrl = "https://cdn.casbin.org"
|
||||
|
14
conf/conf.go
14
conf/conf.go
@ -71,7 +71,10 @@ func GetConfigInt64(key string) (int64, error) {
|
||||
|
||||
func GetConfigDataSourceName() string {
|
||||
dataSourceName := GetConfigString("dataSourceName")
|
||||
return ReplaceDataSourceNameByDocker(dataSourceName)
|
||||
}
|
||||
|
||||
func ReplaceDataSourceNameByDocker(dataSourceName string) string {
|
||||
runningInDocker := os.Getenv("RUNNING_IN_DOCKER")
|
||||
if runningInDocker == "true" {
|
||||
// https://stackoverflow.com/questions/48546124/what-is-linux-equivalent-of-host-docker-internal
|
||||
@ -81,7 +84,6 @@ func GetConfigDataSourceName() string {
|
||||
dataSourceName = strings.ReplaceAll(dataSourceName, "localhost", "host.docker.internal")
|
||||
}
|
||||
}
|
||||
|
||||
return dataSourceName
|
||||
}
|
||||
|
||||
@ -108,13 +110,3 @@ func GetConfigBatchSize() int {
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func GetConfigRealDataSourceName(driverName string) string {
|
||||
var dataSourceName string
|
||||
if driverName != "mysql" {
|
||||
dataSourceName = GetConfigDataSourceName()
|
||||
} else {
|
||||
dataSourceName = GetConfigDataSourceName() + GetConfigString("dbName")
|
||||
}
|
||||
return dataSourceName
|
||||
}
|
||||
|
@ -44,6 +44,8 @@ type Response struct {
|
||||
}
|
||||
|
||||
type Captcha struct {
|
||||
Owner string `json:"owner"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
AppKey string `json:"appKey"`
|
||||
Scene string `json:"scene"`
|
||||
@ -93,6 +95,10 @@ func (c *ApiController) Signup() {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if application == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), authForm.Application))
|
||||
return
|
||||
}
|
||||
|
||||
if !application.EnableSignUp {
|
||||
c.ResponseError(c.T("account:The application does not allow to sign up new account"))
|
||||
@ -105,6 +111,11 @@ func (c *ApiController) Signup() {
|
||||
return
|
||||
}
|
||||
|
||||
if organization == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The organization: %s does not exist"), authForm.Organization))
|
||||
return
|
||||
}
|
||||
|
||||
msg := object.CheckUserSignup(application, organization, &authForm, c.GetAcceptLanguage())
|
||||
if msg != "" {
|
||||
c.ResponseError(msg)
|
||||
@ -122,7 +133,12 @@ func (c *ApiController) Signup() {
|
||||
}
|
||||
|
||||
if application.IsSignupItemVisible("Email") && application.GetSignupItemRule("Email") != "No verification" && authForm.Email != "" {
|
||||
checkResult := object.CheckVerificationCode(authForm.Email, authForm.EmailCode, c.GetAcceptLanguage())
|
||||
var checkResult *object.VerifyResult
|
||||
checkResult, err = object.CheckVerificationCode(authForm.Email, authForm.EmailCode, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(c.T(err.Error()))
|
||||
return
|
||||
}
|
||||
if checkResult.Code != object.VerificationSuccess {
|
||||
c.ResponseError(checkResult.Msg)
|
||||
return
|
||||
@ -132,7 +148,13 @@ func (c *ApiController) Signup() {
|
||||
var checkPhone string
|
||||
if application.IsSignupItemVisible("Phone") && application.GetSignupItemRule("Phone") != "No verification" && authForm.Phone != "" {
|
||||
checkPhone, _ = util.GetE164Number(authForm.Phone, authForm.CountryCode)
|
||||
checkResult := object.CheckVerificationCode(checkPhone, authForm.PhoneCode, c.GetAcceptLanguage())
|
||||
|
||||
var checkResult *object.VerifyResult
|
||||
checkResult, err = object.CheckVerificationCode(checkPhone, authForm.PhoneCode, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(c.T(err.Error()))
|
||||
return
|
||||
}
|
||||
if checkResult.Code != object.VerificationSuccess {
|
||||
c.ResponseError(checkResult.Msg)
|
||||
return
|
||||
@ -227,7 +249,7 @@ func (c *ApiController) Signup() {
|
||||
|
||||
if invitation != nil {
|
||||
invitation.UsedCount += 1
|
||||
_, err := object.UpdateInvitation(invitation.GetId(), invitation)
|
||||
_, err := object.UpdateInvitation(invitation.GetId(), invitation, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@ -251,10 +273,8 @@ func (c *ApiController) Signup() {
|
||||
return
|
||||
}
|
||||
|
||||
record := object.NewRecord(c.Ctx)
|
||||
record.Organization = application.Organization
|
||||
record.User = user.Name
|
||||
util.SafeGoroutine(func() { object.AddRecord(record) })
|
||||
c.Ctx.Input.SetParam("recordUserId", user.GetId())
|
||||
c.Ctx.Input.SetParam("recordSignup", "true")
|
||||
|
||||
userId := user.GetId()
|
||||
util.LogInfo(c.Ctx, "API: [%s] is signed up as new user", userId)
|
||||
@ -287,6 +307,7 @@ func (c *ApiController) Logout() {
|
||||
}
|
||||
|
||||
c.ClearUserSession()
|
||||
c.ClearTokenSession()
|
||||
owner, username := util.GetOwnerAndNameFromId(user)
|
||||
_, err := object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID())
|
||||
if err != nil {
|
||||
@ -333,6 +354,7 @@ func (c *ApiController) Logout() {
|
||||
}
|
||||
|
||||
c.ClearUserSession()
|
||||
c.ClearTokenSession()
|
||||
// TODO https://github.com/casdoor/casdoor/pull/1494#discussion_r1095675265
|
||||
owner, username := util.GetOwnerAndNameFromId(user)
|
||||
|
||||
@ -413,6 +435,17 @@ func (c *ApiController) GetAccount() {
|
||||
return
|
||||
}
|
||||
|
||||
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{
|
||||
Status: "ok",
|
||||
Sub: user.Id,
|
||||
@ -439,7 +472,12 @@ func (c *ApiController) GetUserinfo() {
|
||||
|
||||
scope, aud := c.GetSessionOidc()
|
||||
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.ServeJSON()
|
||||
@ -494,10 +532,12 @@ func (c *ApiController) GetCaptcha() {
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(Captcha{Type: captchaProvider.Type, CaptchaId: id, CaptchaImage: img})
|
||||
c.ResponseOk(Captcha{Owner: captchaProvider.Owner, Name: captchaProvider.Name, Type: captchaProvider.Type, CaptchaId: id, CaptchaImage: img})
|
||||
return
|
||||
} else if captchaProvider.Type != "" {
|
||||
c.ResponseOk(Captcha{
|
||||
Owner: captchaProvider.Owner,
|
||||
Name: captchaProvider.Name,
|
||||
Type: captchaProvider.Type,
|
||||
SubType: captchaProvider.SubType,
|
||||
ClientId: captchaProvider.ClientId,
|
||||
|
@ -139,6 +139,10 @@ func (c *ApiController) GetUserApplication() {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if application == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("general:The organization: %s should have one application at least"), user.Owner))
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(object.GetMaskedApplication(application, userId))
|
||||
}
|
||||
@ -173,7 +177,7 @@ func (c *ApiController) GetOrganizationApplications() {
|
||||
return
|
||||
}
|
||||
|
||||
applications, err = object.GetAllowedApplications(applications, userId)
|
||||
applications, err = object.GetAllowedApplications(applications, userId, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@ -190,13 +194,19 @@ func (c *ApiController) GetOrganizationApplications() {
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
application, err := object.GetPaginationOrganizationApplications(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
applications, err := object.GetPaginationOrganizationApplications(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
applications := object.GetMaskedApplications(application, userId)
|
||||
applications, err = object.GetAllowedApplications(applications, userId, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
applications = object.GetMaskedApplications(applications, userId)
|
||||
c.ResponseOk(applications, paginator.Nums())
|
||||
}
|
||||
}
|
||||
|
@ -19,12 +19,11 @@ import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/casdoor/casdoor/captcha"
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
@ -37,11 +36,6 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
var (
|
||||
wechatScanType string
|
||||
lock sync.RWMutex
|
||||
)
|
||||
|
||||
func codeToResponse(code *object.Code) *Response {
|
||||
if code.Code == "" {
|
||||
return &Response{Status: "error", Msg: code.Message, Data: code.Code}
|
||||
@ -333,7 +327,38 @@ func (c *ApiController) Login() {
|
||||
}
|
||||
|
||||
var user *object.User
|
||||
if authForm.Password == "" {
|
||||
if authForm.SigninMethod == "Face ID" {
|
||||
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
|
||||
}
|
||||
|
||||
if err := object.CheckFaceId(user, authForm.FaceId, c.GetAcceptLanguage()); err != nil {
|
||||
c.ResponseError(err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
} else if authForm.Password == "" {
|
||||
if user, err = object.GetUserByFields(authForm.Organization, authForm.Username); err != nil {
|
||||
c.ResponseError(err.Error(), nil)
|
||||
return
|
||||
@ -483,10 +508,7 @@ func (c *ApiController) Login() {
|
||||
|
||||
resp = c.HandleLoggedIn(application, user, &authForm)
|
||||
|
||||
record := object.NewRecord(c.Ctx)
|
||||
record.Organization = application.Organization
|
||||
record.User = user.Name
|
||||
util.SafeGoroutine(func() { object.AddRecord(record) })
|
||||
c.Ctx.Input.SetParam("recordUserId", user.GetId())
|
||||
}
|
||||
} else if authForm.Provider != "" {
|
||||
var application *object.Application
|
||||
@ -607,10 +629,7 @@ func (c *ApiController) Login() {
|
||||
}
|
||||
resp = c.HandleLoggedIn(application, user, &authForm)
|
||||
|
||||
record := object.NewRecord(c.Ctx)
|
||||
record.Organization = application.Organization
|
||||
record.User = user.Name
|
||||
util.SafeGoroutine(func() { object.AddRecord(record) })
|
||||
c.Ctx.Input.SetParam("recordUserId", user.GetId())
|
||||
} else if provider.Category == "OAuth" || provider.Category == "Web3" {
|
||||
// Sign up via OAuth
|
||||
if application.EnableLinkWithEmail {
|
||||
@ -743,16 +762,8 @@ func (c *ApiController) Login() {
|
||||
|
||||
resp = c.HandleLoggedIn(application, user, &authForm)
|
||||
|
||||
record := object.NewRecord(c.Ctx)
|
||||
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) })
|
||||
c.Ctx.Input.SetParam("recordUserId", user.GetId())
|
||||
c.Ctx.Input.SetParam("recordSignup", "true")
|
||||
} else if provider.Category == "SAML" {
|
||||
// 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))}
|
||||
@ -854,10 +865,7 @@ func (c *ApiController) Login() {
|
||||
resp = c.HandleLoggedIn(application, user, &authForm)
|
||||
c.setMfaUserSession("")
|
||||
|
||||
record := object.NewRecord(c.Ctx)
|
||||
record.Organization = application.Organization
|
||||
record.User = user.Name
|
||||
util.SafeGoroutine(func() { object.AddRecord(record) })
|
||||
c.Ctx.Input.SetParam("recordUserId", user.GetId())
|
||||
} else {
|
||||
if c.GetSessionUsername() != "" {
|
||||
// user already signed in to Casdoor, so let the user click the avatar button to do the quick sign-in
|
||||
@ -876,10 +884,7 @@ func (c *ApiController) Login() {
|
||||
user := c.getCurrentUser()
|
||||
resp = c.HandleLoggedIn(application, user, &authForm)
|
||||
|
||||
record := object.NewRecord(c.Ctx)
|
||||
record.Organization = application.Organization
|
||||
record.User = user.Name
|
||||
util.SafeGoroutine(func() { object.AddRecord(record) })
|
||||
c.Ctx.Input.SetParam("recordUserId", user.GetId())
|
||||
} else {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:Unknown authentication type (not password or provider), form = %s"), util.StructToJson(authForm)))
|
||||
return
|
||||
@ -896,6 +901,7 @@ func (c *ApiController) GetSamlLogin() {
|
||||
authURL, method, err := object.GenerateSamlRequest(providerId, relayState, c.Ctx.Request.Host, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
c.ResponseOk(authURL, method)
|
||||
}
|
||||
@ -906,62 +912,126 @@ func (c *ApiController) HandleSamlLogin() {
|
||||
decode, err := base64.StdEncoding.DecodeString(relayState)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
slice := strings.Split(string(decode), "&")
|
||||
relayState = url.QueryEscape(relayState)
|
||||
samlResponse = url.QueryEscape(samlResponse)
|
||||
targetUrl := fmt.Sprintf("%s?relayState=%s&samlResponse=%s",
|
||||
slice[4], relayState, samlResponse)
|
||||
c.Redirect(targetUrl, 303)
|
||||
c.Redirect(targetUrl, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// HandleOfficialAccountEvent ...
|
||||
// @Tag System API
|
||||
// @Title HandleOfficialAccountEvent
|
||||
// @router /webhook [POST]
|
||||
// @Success 200 {object} object.Userinfo The Response object
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
func (c *ApiController) HandleOfficialAccountEvent() {
|
||||
respBytes, err := ioutil.ReadAll(c.Ctx.Request.Body)
|
||||
if c.Ctx.Request.Method == "GET" {
|
||||
s := c.Ctx.Request.FormValue("echostr")
|
||||
echostr, _ := strconv.Atoi(s)
|
||||
c.SetData(echostr)
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
respBytes, err := io.ReadAll(c.Ctx.Request.Body)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
signature := c.Input().Get("signature")
|
||||
timestamp := c.Input().Get("timestamp")
|
||||
nonce := c.Input().Get("nonce")
|
||||
var data struct {
|
||||
MsgType string `xml:"MsgType"`
|
||||
Event string `xml:"Event"`
|
||||
EventKey string `xml:"EventKey"`
|
||||
MsgType string `xml:"MsgType"`
|
||||
Event string `xml:"Event"`
|
||||
EventKey string `xml:"EventKey"`
|
||||
FromUserName string `xml:"FromUserName"`
|
||||
Ticket string `xml:"Ticket"`
|
||||
}
|
||||
err = xml.Unmarshal(respBytes, &data)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
if data.EventKey != "" {
|
||||
wechatScanType = data.Event
|
||||
if strings.ToUpper(data.Event) != "SCAN" && strings.ToUpper(data.Event) != "SUBSCRIBE" {
|
||||
c.Ctx.WriteString("")
|
||||
return
|
||||
}
|
||||
if data.Ticket == "" {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
providerId := data.EventKey
|
||||
provider, err := object.GetProvider(providerId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if data.Ticket == "" {
|
||||
c.ResponseError("empty ticket")
|
||||
return
|
||||
}
|
||||
if !idp.VerifyWechatSignature(provider.Content, nonce, timestamp, signature) {
|
||||
c.ResponseError("invalid signature")
|
||||
return
|
||||
}
|
||||
|
||||
idp.Lock.Lock()
|
||||
if idp.WechatCacheMap == nil {
|
||||
idp.WechatCacheMap = make(map[string]idp.WechatCacheMapValue)
|
||||
}
|
||||
idp.WechatCacheMap[data.Ticket] = idp.WechatCacheMapValue{
|
||||
IsScanned: true,
|
||||
WechatUnionId: data.FromUserName,
|
||||
}
|
||||
idp.Lock.Unlock()
|
||||
|
||||
c.Ctx.WriteString("")
|
||||
}
|
||||
|
||||
// GetWebhookEventType ...
|
||||
// @Tag System API
|
||||
// @Title GetWebhookEventType
|
||||
// @router /get-webhook-event [GET]
|
||||
// @Success 200 {object} object.Userinfo The Response object
|
||||
// @Param ticket query string true "The eventId of QRCode"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
func (c *ApiController) GetWebhookEventType() {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
resp := &Response{
|
||||
Status: "ok",
|
||||
Msg: "",
|
||||
Data: wechatScanType,
|
||||
ticket := c.Input().Get("ticket")
|
||||
|
||||
idp.Lock.RLock()
|
||||
_, ok := idp.WechatCacheMap[ticket]
|
||||
idp.Lock.RUnlock()
|
||||
if !ok {
|
||||
c.ResponseError("ticket not found")
|
||||
return
|
||||
}
|
||||
c.Data["json"] = resp
|
||||
wechatScanType = ""
|
||||
c.ServeJSON()
|
||||
|
||||
c.ResponseOk("SCAN", ticket)
|
||||
}
|
||||
|
||||
// GetQRCode
|
||||
// @Tag System API
|
||||
// @Title GetWechatQRCode
|
||||
// @router /get-qrcode [GET]
|
||||
// @Param id query string true "The id ( owner/name ) of provider"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
func (c *ApiController) GetQRCode() {
|
||||
providerId := c.Input().Get("id")
|
||||
provider, err := object.GetProvider(providerId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
code, ticket, err := idp.GetWechatOfficialAccountQRCode(provider.ClientId2, provider.ClientSecret2, providerId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(code, ticket)
|
||||
}
|
||||
|
||||
// GetCaptchaStatus
|
||||
|
@ -122,6 +122,15 @@ func (c *ApiController) GetSessionUsername() 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 {
|
||||
clientId := c.GetSession("aud")
|
||||
if clientId == nil {
|
||||
@ -141,6 +150,10 @@ func (c *ApiController) ClearUserSession() {
|
||||
c.SetSessionData(nil)
|
||||
}
|
||||
|
||||
func (c *ApiController) ClearTokenSession() {
|
||||
c.SetSessionToken("")
|
||||
}
|
||||
|
||||
func (c *ApiController) GetSessionOidc() (string, string) {
|
||||
sessionData := c.GetSessionData()
|
||||
if sessionData != nil &&
|
||||
@ -167,6 +180,10 @@ func (c *ApiController) SetSessionUsername(user string) {
|
||||
c.SetSession("username", user)
|
||||
}
|
||||
|
||||
func (c *ApiController) SetSessionToken(accessToken string) {
|
||||
c.SetSession("accessToken", accessToken)
|
||||
}
|
||||
|
||||
// GetSessionData ...
|
||||
func (c *ApiController) GetSessionData() *SessionData {
|
||||
session := c.GetSession("SessionData")
|
||||
|
@ -85,7 +85,7 @@ func (c *ApiController) Enforce() {
|
||||
return
|
||||
}
|
||||
if permission == nil {
|
||||
c.ResponseError(fmt.Sprintf("permission: %s doesn't exist", permissionId))
|
||||
c.ResponseError(fmt.Sprintf(c.T("permission:The permission: \"%s\" doesn't exist"), permissionId))
|
||||
return
|
||||
}
|
||||
|
||||
@ -121,6 +121,10 @@ func (c *ApiController) Enforce() {
|
||||
}
|
||||
} else if owner != "" {
|
||||
permissions, err = object.GetPermissions(owner)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
c.ResponseError(c.T("general:Missing parameter"))
|
||||
return
|
||||
@ -205,7 +209,7 @@ func (c *ApiController) BatchEnforce() {
|
||||
return
|
||||
}
|
||||
if permission == nil {
|
||||
c.ResponseError(fmt.Sprintf("permission: %s doesn't exist", permissionId))
|
||||
c.ResponseError(fmt.Sprintf(c.T("permission:The permission: \"%s\" doesn't exist"), permissionId))
|
||||
return
|
||||
}
|
||||
|
||||
@ -235,6 +239,10 @@ func (c *ApiController) BatchEnforce() {
|
||||
}
|
||||
} else if owner != "" {
|
||||
permissions, err = object.GetPermissions(owner)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
c.ResponseError(c.T("general:Missing parameter"))
|
||||
return
|
||||
|
@ -68,7 +68,7 @@ func (c *ApiController) GetCerts() {
|
||||
// GetGlobalCerts
|
||||
// @Title GetGlobalCerts
|
||||
// @Tag Cert API
|
||||
// @Description get globle certs
|
||||
// @Description get global certs
|
||||
// @Success 200 {array} object.Cert The Response object
|
||||
// @router /get-global-certs [get]
|
||||
func (c *ApiController) GetGlobalCerts() {
|
||||
|
55
controllers/face.go
Normal file
55
controllers/face.go
Normal file
@ -0,0 +1,55 @@
|
||||
// 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()
|
||||
}
|
@ -43,13 +43,20 @@ func (c *ApiController) GetGroups() {
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
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 {
|
||||
limit := util.ParseInt(limit)
|
||||
count, err := object.GetGroupCount(owner, field, value)
|
||||
@ -64,6 +71,12 @@ func (c *ApiController) GetGroups() {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
} else {
|
||||
err = object.ExtendGroupsWithUsers(groups)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(groups, paginator.Nums())
|
||||
}
|
||||
}
|
||||
@ -84,6 +97,13 @@ func (c *ApiController) GetGroup() {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err = object.ExtendGroupWithUsers(group)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(group)
|
||||
}
|
||||
|
||||
|
@ -84,6 +84,32 @@ func (c *ApiController) GetInvitation() {
|
||||
c.ResponseOk(invitation)
|
||||
}
|
||||
|
||||
// GetInvitationCodeInfo
|
||||
// @Title GetInvitationCodeInfo
|
||||
// @Tag Invitation API
|
||||
// @Description get invitation code information
|
||||
// @Param code query string true "Invitation code"
|
||||
// @Success 200 {object} object.Invitation The Response object
|
||||
// @router /get-invitation-info [get]
|
||||
func (c *ApiController) GetInvitationCodeInfo() {
|
||||
code := c.Input().Get("code")
|
||||
applicationId := c.Input().Get("applicationId")
|
||||
|
||||
application, err := object.GetApplication(applicationId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
invitation, msg := object.GetInvitationByCode(code, application.Organization, c.GetAcceptLanguage())
|
||||
if msg != "" {
|
||||
c.ResponseError(msg)
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(object.GetMaskedInvitation(invitation))
|
||||
}
|
||||
|
||||
// UpdateInvitation
|
||||
// @Title UpdateInvitation
|
||||
// @Tag Invitation API
|
||||
@ -102,7 +128,7 @@ func (c *ApiController) UpdateInvitation() {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateInvitation(id, &invitation))
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateInvitation(id, &invitation, c.GetAcceptLanguage()))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
@ -121,7 +147,7 @@ func (c *ApiController) AddInvitation() {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.AddInvitation(&invitation))
|
||||
c.Data["json"] = wrapActionResponse(object.AddInvitation(&invitation, c.GetAcceptLanguage()))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,14 @@ import (
|
||||
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
MfaRecoveryCodesSession = "mfa_recovery_codes"
|
||||
MfaCountryCodeSession = "mfa_country_code"
|
||||
MfaDestSession = "mfa_dest"
|
||||
MfaTotpSecretSession = "mfa_totp_secret"
|
||||
)
|
||||
|
||||
// MfaSetupInitiate
|
||||
@ -57,12 +65,20 @@ func (c *ApiController) MfaSetupInitiate() {
|
||||
return
|
||||
}
|
||||
|
||||
mfaProps, err := MfaUtil.Initiate(c.Ctx, user.GetId())
|
||||
mfaProps, err := MfaUtil.Initiate(user.GetId())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
recoveryCode := uuid.NewString()
|
||||
c.SetSession(MfaRecoveryCodesSession, recoveryCode)
|
||||
if mfaType == object.TotpType {
|
||||
c.SetSession(MfaTotpSecretSession, mfaProps.Secret)
|
||||
}
|
||||
|
||||
mfaProps.RecoveryCodes = []string{recoveryCode}
|
||||
|
||||
resp := mfaProps
|
||||
c.ResponseOk(resp)
|
||||
}
|
||||
@ -83,13 +99,46 @@ func (c *ApiController) MfaSetupVerify() {
|
||||
c.ResponseError("missing auth type or passcode")
|
||||
return
|
||||
}
|
||||
mfaUtil := object.GetMfaUtil(mfaType, nil)
|
||||
|
||||
config := &object.MfaProps{
|
||||
MfaType: mfaType,
|
||||
}
|
||||
if mfaType == object.TotpType {
|
||||
secret := c.GetSession(MfaTotpSecretSession)
|
||||
if secret == nil {
|
||||
c.ResponseError("totp secret is missing")
|
||||
return
|
||||
}
|
||||
config.Secret = secret.(string)
|
||||
} else if mfaType == object.SmsType {
|
||||
dest := c.GetSession(MfaDestSession)
|
||||
if dest == nil {
|
||||
c.ResponseError("destination is missing")
|
||||
return
|
||||
}
|
||||
config.Secret = dest.(string)
|
||||
countryCode := c.GetSession(MfaCountryCodeSession)
|
||||
if countryCode == nil {
|
||||
c.ResponseError("country code is missing")
|
||||
return
|
||||
}
|
||||
config.CountryCode = countryCode.(string)
|
||||
} else if mfaType == object.EmailType {
|
||||
dest := c.GetSession(MfaDestSession)
|
||||
if dest == nil {
|
||||
c.ResponseError("destination is missing")
|
||||
return
|
||||
}
|
||||
config.Secret = dest.(string)
|
||||
}
|
||||
|
||||
mfaUtil := object.GetMfaUtil(mfaType, config)
|
||||
if mfaUtil == nil {
|
||||
c.ResponseError("Invalid multi-factor authentication type")
|
||||
return
|
||||
}
|
||||
|
||||
err := mfaUtil.SetupVerify(c.Ctx, passcode)
|
||||
err := mfaUtil.SetupVerify(passcode)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
} else {
|
||||
@ -122,18 +171,69 @@ func (c *ApiController) MfaSetupEnable() {
|
||||
return
|
||||
}
|
||||
|
||||
mfaUtil := object.GetMfaUtil(mfaType, nil)
|
||||
config := &object.MfaProps{
|
||||
MfaType: mfaType,
|
||||
}
|
||||
|
||||
if mfaType == object.TotpType {
|
||||
secret := c.GetSession(MfaTotpSecretSession)
|
||||
if secret == nil {
|
||||
c.ResponseError("totp secret is missing")
|
||||
return
|
||||
}
|
||||
config.Secret = secret.(string)
|
||||
} else if mfaType == object.EmailType {
|
||||
if user.Email == "" {
|
||||
dest := c.GetSession(MfaDestSession)
|
||||
if dest == nil {
|
||||
c.ResponseError("destination is missing")
|
||||
return
|
||||
}
|
||||
user.Email = dest.(string)
|
||||
}
|
||||
} else if mfaType == object.SmsType {
|
||||
if user.Phone == "" {
|
||||
dest := c.GetSession(MfaDestSession)
|
||||
if dest == nil {
|
||||
c.ResponseError("destination is missing")
|
||||
return
|
||||
}
|
||||
user.Phone = dest.(string)
|
||||
countryCode := c.GetSession(MfaCountryCodeSession)
|
||||
if countryCode == nil {
|
||||
c.ResponseError("country code is missing")
|
||||
return
|
||||
}
|
||||
user.CountryCode = countryCode.(string)
|
||||
}
|
||||
}
|
||||
recoveryCodes := c.GetSession(MfaRecoveryCodesSession)
|
||||
if recoveryCodes == nil {
|
||||
c.ResponseError("recovery codes is missing")
|
||||
return
|
||||
}
|
||||
config.RecoveryCodes = []string{recoveryCodes.(string)}
|
||||
|
||||
mfaUtil := object.GetMfaUtil(mfaType, config)
|
||||
if mfaUtil == nil {
|
||||
c.ResponseError("Invalid multi-factor authentication type")
|
||||
return
|
||||
}
|
||||
|
||||
err = mfaUtil.Enable(c.Ctx, user)
|
||||
err = mfaUtil.Enable(user)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.DelSession(MfaRecoveryCodesSession)
|
||||
if mfaType == object.TotpType {
|
||||
c.DelSession(MfaTotpSecretSession)
|
||||
} else {
|
||||
c.DelSession(MfaCountryCodeSession)
|
||||
c.DelSession(MfaDestSession)
|
||||
}
|
||||
|
||||
c.ResponseOk(http.StatusText(http.StatusOK))
|
||||
}
|
||||
|
||||
|
@ -141,6 +141,20 @@ func (c *ApiController) GetProvider() {
|
||||
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
|
||||
// @Title UpdateProvider
|
||||
// @Tag Provider API
|
||||
@ -159,6 +173,11 @@ func (c *ApiController) UpdateProvider() {
|
||||
return
|
||||
}
|
||||
|
||||
ok := c.requireProviderPermission(&provider)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateProvider(id, &provider))
|
||||
c.ServeJSON()
|
||||
}
|
||||
@ -184,11 +203,17 @@ func (c *ApiController) AddProvider() {
|
||||
return
|
||||
}
|
||||
|
||||
if err := checkQuotaForProvider(int(count)); err != nil {
|
||||
err = checkQuotaForProvider(int(count))
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ok := c.requireProviderPermission(&provider)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.AddProvider(&provider))
|
||||
c.ServeJSON()
|
||||
}
|
||||
@ -208,6 +233,11 @@ func (c *ApiController) DeleteProvider() {
|
||||
return
|
||||
}
|
||||
|
||||
ok := c.requireProviderPermission(&provider)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.DeleteProvider(&provider))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
128
controllers/record.go
Normal file
128
controllers/record.go
Normal file
@ -0,0 +1,128 @@
|
||||
// Copyright 2021 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/casvisor/casvisor-go-sdk/casvisorsdk"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetRecords
|
||||
// @Title GetRecords
|
||||
// @Tag Record API
|
||||
// @Description get all records
|
||||
// @Param pageSize query string true "The size of each page"
|
||||
// @Param p query string true "The number of the page"
|
||||
// @Success 200 {object} object.Record The Response object
|
||||
// @router /get-records [get]
|
||||
func (c *ApiController) GetRecords() {
|
||||
organization, ok := c.RequireAdmin()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
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")
|
||||
organizationName := c.Input().Get("organizationName")
|
||||
|
||||
if limit == "" || page == "" {
|
||||
records, err := object.GetRecords()
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(records)
|
||||
} else {
|
||||
limit := util.ParseInt(limit)
|
||||
if c.IsGlobalAdmin() && organizationName != "" {
|
||||
organization = organizationName
|
||||
}
|
||||
filterRecord := &casvisorsdk.Record{Organization: organization}
|
||||
count, err := object.GetRecordCount(field, value, filterRecord)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
records, err := object.GetPaginationRecords(paginator.Offset(), limit, field, value, sortField, sortOrder, filterRecord)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(records, paginator.Nums())
|
||||
}
|
||||
}
|
||||
|
||||
// GetRecordsByFilter
|
||||
// @Tag Record API
|
||||
// @Title GetRecordsByFilter
|
||||
// @Description get records by filter
|
||||
// @Param filter body string true "filter Record message"
|
||||
// @Success 200 {object} object.Record The Response object
|
||||
// @router /get-records-filter [post]
|
||||
func (c *ApiController) GetRecordsByFilter() {
|
||||
_, ok := c.RequireAdmin()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
body := string(c.Ctx.Input.RequestBody)
|
||||
|
||||
record := &casvisorsdk.Record{}
|
||||
err := util.JsonToStruct(body, record)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
records, err := object.GetRecordsByField(record)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(records)
|
||||
}
|
||||
|
||||
// AddRecord
|
||||
// @Title AddRecord
|
||||
// @Tag Record API
|
||||
// @Description add a record
|
||||
// @Param body body object.Record true "The details of the record"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /add-record [post]
|
||||
func (c *ApiController) AddRecord() {
|
||||
var record casvisorsdk.Record
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &record)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.AddRecord(&record))
|
||||
c.ServeJSON()
|
||||
}
|
@ -52,6 +52,15 @@ func (c *ApiController) GetResources() {
|
||||
sortField := c.Input().Get("sortField")
|
||||
sortOrder := c.Input().Get("sortOrder")
|
||||
|
||||
isOrgAdmin, ok := c.IsOrgAdmin()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if isOrgAdmin {
|
||||
user = ""
|
||||
}
|
||||
|
||||
if sortField == "Direct" {
|
||||
provider, err := c.GetProviderFromContext("Storage")
|
||||
if err != nil {
|
||||
|
@ -16,6 +16,7 @@ package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/casdoor/casdoor/object"
|
||||
)
|
||||
@ -34,7 +35,13 @@ func (c *ApiController) GetSamlMeta() {
|
||||
return
|
||||
}
|
||||
|
||||
metadata, err := object.GetSamlMeta(application, host)
|
||||
enablePostBinding, err := c.GetBool("enablePostBinding", false)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
metadata, err := object.GetSamlMeta(application, host, enablePostBinding)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@ -43,3 +50,17 @@ func (c *ApiController) GetSamlMeta() {
|
||||
c.Data["xml"] = metadata
|
||||
c.ServeXML()
|
||||
}
|
||||
|
||||
func (c *ApiController) HandleSamlRedirect() {
|
||||
host := c.Ctx.Request.Host
|
||||
|
||||
owner := c.Ctx.Input.Param(":owner")
|
||||
application := c.Ctx.Input.Param(":application")
|
||||
|
||||
relayState := c.Input().Get("RelayState")
|
||||
samlRequest := c.Input().Get("SAMLRequest")
|
||||
|
||||
targetURL := object.GetSamlRedirectAddress(owner, application, relayState, samlRequest, host)
|
||||
|
||||
c.Redirect(targetURL, http.StatusSeeOther)
|
||||
}
|
||||
|
@ -60,7 +60,6 @@ func (c *ApiController) SendEmail() {
|
||||
}
|
||||
|
||||
var emailForm EmailForm
|
||||
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &emailForm)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@ -87,7 +86,7 @@ func (c *ApiController) SendEmail() {
|
||||
|
||||
// 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" {
|
||||
err := object.DailSmtpServer(provider)
|
||||
err = object.DailSmtpServer(provider)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@ -112,20 +111,25 @@ func (c *ApiController) SendEmail() {
|
||||
return
|
||||
}
|
||||
|
||||
code := "123456"
|
||||
content := emailForm.Content
|
||||
if content == "" {
|
||||
code := "123456"
|
||||
|
||||
// "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes."
|
||||
content := strings.Replace(provider.Content, "%s", code, 1)
|
||||
if !strings.HasPrefix(userId, "app/") {
|
||||
var user *object.User
|
||||
user, err = object.GetUser(userId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
// "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes."
|
||||
content = strings.Replace(provider.Content, "%s", code, 1)
|
||||
if !strings.HasPrefix(userId, "app/") {
|
||||
var user *object.User
|
||||
user, err = object.GetUser(userId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if user != nil {
|
||||
content = strings.Replace(content, "%{user.friendlyName}", user.GetFriendlyName(), 1)
|
||||
userString := "Hi"
|
||||
if user != nil {
|
||||
userString = user.GetFriendlyName()
|
||||
}
|
||||
content = strings.Replace(content, "%{user.friendlyName}", userString, 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,3 +168,20 @@ func (c *ApiController) RunSyncer() {
|
||||
|
||||
c.ResponseOk()
|
||||
}
|
||||
|
||||
func (c *ApiController) TestSyncerDb() {
|
||||
var syncer object.Syncer
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err = object.TestSyncerDb(syncer)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk()
|
||||
}
|
||||
|
@ -47,6 +47,11 @@ func (c *ApiController) GetSystemInfo() {
|
||||
// @router /get-version-info [get]
|
||||
func (c *ApiController) GetVersionInfo() {
|
||||
versionInfo, err := util.GetVersionInfo()
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if versionInfo.Version != "" {
|
||||
c.ResponseOk(versionInfo)
|
||||
return
|
||||
|
@ -164,6 +164,7 @@ func (c *ApiController) GetOAuthToken() {
|
||||
code := c.Input().Get("code")
|
||||
verifier := c.Input().Get("code_verifier")
|
||||
scope := c.Input().Get("scope")
|
||||
nonce := c.Input().Get("nonce")
|
||||
username := c.Input().Get("username")
|
||||
password := c.Input().Get("password")
|
||||
tag := c.Input().Get("tag")
|
||||
@ -197,6 +198,9 @@ func (c *ApiController) GetOAuthToken() {
|
||||
if scope == "" {
|
||||
scope = tokenRequest.Scope
|
||||
}
|
||||
if nonce == "" {
|
||||
nonce = tokenRequest.Nonce
|
||||
}
|
||||
if username == "" {
|
||||
username = tokenRequest.Username
|
||||
}
|
||||
@ -216,7 +220,7 @@ func (c *ApiController) GetOAuthToken() {
|
||||
}
|
||||
|
||||
host := c.Ctx.Request.Host
|
||||
token, err := object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, username, password, host, refreshToken, tag, avatar, c.GetAcceptLanguage())
|
||||
token, err := object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, nonce, username, password, host, refreshToken, tag, avatar, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@ -271,6 +275,14 @@ func (c *ApiController) RefreshToken() {
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
func (c *ApiController) ResponseTokenError(errorMsg string) {
|
||||
c.Data["json"] = &object.TokenError{
|
||||
Error: errorMsg,
|
||||
}
|
||||
c.SetTokenErrorHttpStatus()
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// IntrospectToken
|
||||
// @Title IntrospectToken
|
||||
// @Tag Login API
|
||||
@ -293,40 +305,34 @@ func (c *ApiController) IntrospectToken() {
|
||||
clientId = c.Input().Get("client_id")
|
||||
clientSecret = c.Input().Get("client_secret")
|
||||
if clientId == "" || clientSecret == "" {
|
||||
c.ResponseError(c.T("token:Empty clientId or clientSecret"))
|
||||
c.Data["json"] = &object.TokenError{
|
||||
Error: object.InvalidRequest,
|
||||
}
|
||||
c.SetTokenErrorHttpStatus()
|
||||
c.ServeJSON()
|
||||
c.ResponseTokenError(object.InvalidRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
application, err := object.GetApplicationByClientId(clientId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
c.ResponseTokenError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if application == nil || application.ClientSecret != clientSecret {
|
||||
c.ResponseError(c.T("token:Invalid application or wrong clientSecret"))
|
||||
c.Data["json"] = &object.TokenError{
|
||||
Error: object.InvalidClient,
|
||||
}
|
||||
c.SetTokenErrorHttpStatus()
|
||||
return
|
||||
}
|
||||
token, err := object.GetTokenByTokenAndApplication(tokenValue, application.Name)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
c.ResponseTokenError(c.T("token:Invalid application or wrong clientSecret"))
|
||||
return
|
||||
}
|
||||
|
||||
tokenTypeHint := c.Input().Get("token_type_hint")
|
||||
token, err := object.GetTokenByTokenValue(tokenValue, tokenTypeHint)
|
||||
if err != nil {
|
||||
c.ResponseTokenError(err.Error())
|
||||
return
|
||||
}
|
||||
if token == nil {
|
||||
c.Data["json"] = &object.IntrospectionResponse{Active: false}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
jwtToken, err := object.ParseJwtTokenByApplication(tokenValue, application)
|
||||
if err != nil || jwtToken.Valid() != nil {
|
||||
// and token revoked case. but we not implement
|
||||
|
167
controllers/transaction.go
Normal file
167
controllers/transaction.go
Normal file
@ -0,0 +1,167 @@
|
||||
// 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()
|
||||
}
|
@ -21,6 +21,7 @@ type TokenRequest struct {
|
||||
Code string `json:"code"`
|
||||
Verifier string `json:"code_verifier"`
|
||||
Scope string `json:"scope"`
|
||||
Nonce string `json:"nonce"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Tag string `json:"tag"`
|
||||
|
@ -156,6 +156,10 @@ func (c *ApiController) GetUser() {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if userFromUserId == nil {
|
||||
c.ResponseOk(nil)
|
||||
return
|
||||
}
|
||||
|
||||
id = util.GetId(userFromUserId.Owner, userFromUserId.Name)
|
||||
}
|
||||
@ -200,7 +204,7 @@ func (c *ApiController) GetUser() {
|
||||
return
|
||||
}
|
||||
if organization == nil {
|
||||
c.ResponseError(fmt.Sprintf("the organization: %s is not found", owner))
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The organization: %s does not exist"), owner))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -108,12 +108,12 @@ func (c *ApiController) RequireSignedInUser() (*object.User, bool) {
|
||||
c.ResponseError(err.Error())
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
c.ClearUserSession()
|
||||
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId))
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return user, true
|
||||
}
|
||||
|
||||
@ -127,9 +127,39 @@ func (c *ApiController) RequireAdmin() (string, bool) {
|
||||
if user.Owner == "built-in" {
|
||||
return "", true
|
||||
}
|
||||
|
||||
if !user.IsAdmin {
|
||||
c.ResponseError(c.T("general:this operation requires administrator to perform"))
|
||||
return "", false
|
||||
}
|
||||
|
||||
return user.Owner, true
|
||||
}
|
||||
|
||||
func (c *ApiController) IsOrgAdmin() (bool, bool) {
|
||||
userId, ok := c.RequireSignedIn()
|
||||
if !ok {
|
||||
return false, true
|
||||
}
|
||||
|
||||
if strings.HasPrefix(userId, "app/") {
|
||||
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 ...
|
||||
func (c *ApiController) IsMaskedEnabled() (bool, bool) {
|
||||
isMaskEnabled := true
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/casdoor/casdoor/captcha"
|
||||
"github.com/casdoor/casdoor/form"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
@ -35,6 +36,90 @@ const (
|
||||
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 ...
|
||||
// @Title SendVerificationCode
|
||||
// @Tag Verification API
|
||||
@ -161,16 +246,16 @@ func (c *ApiController) SendVerificationCode() {
|
||||
vform.Dest = mfaProps.Secret
|
||||
}
|
||||
} else if vform.Method == MfaSetupVerification {
|
||||
c.SetSession(object.MfaDestSession, vform.Dest)
|
||||
c.SetSession(MfaDestSession, vform.Dest)
|
||||
}
|
||||
|
||||
provider, err := application.GetEmailProvider()
|
||||
provider, err = application.GetEmailProvider(vform.Method)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if provider == nil {
|
||||
c.ResponseError(fmt.Sprintf("please add an Email provider to the \"Providers\" list for the application: %s", application.Name))
|
||||
c.ResponseError(fmt.Sprintf(c.T("verification:please add an Email provider to the \"Providers\" list for the application: %s"), application.Name))
|
||||
return
|
||||
}
|
||||
|
||||
@ -198,8 +283,8 @@ func (c *ApiController) SendVerificationCode() {
|
||||
}
|
||||
|
||||
if vform.Method == MfaSetupVerification {
|
||||
c.SetSession(object.MfaCountryCodeSession, vform.CountryCode)
|
||||
c.SetSession(object.MfaDestSession, vform.Dest)
|
||||
c.SetSession(MfaCountryCodeSession, vform.CountryCode)
|
||||
c.SetSession(MfaDestSession, vform.Dest)
|
||||
}
|
||||
} else if vform.Method == MfaAuthVerification {
|
||||
mfaProps := user.GetPreferredMfaProps(false)
|
||||
@ -210,13 +295,13 @@ func (c *ApiController) SendVerificationCode() {
|
||||
vform.CountryCode = mfaProps.CountryCode
|
||||
}
|
||||
|
||||
provider, err := application.GetSmsProvider()
|
||||
provider, err = application.GetSmsProvider(vform.Method)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if provider == nil {
|
||||
c.ResponseError(fmt.Sprintf("please add a SMS provider to the \"Providers\" list for the application: %s", application.Name))
|
||||
c.ResponseError(fmt.Sprintf(c.T("verification:please add a SMS provider to the \"Providers\" list for the application: %s"), application.Name))
|
||||
return
|
||||
}
|
||||
|
||||
@ -343,7 +428,12 @@ func (c *ApiController) ResetEmailOrPhone() {
|
||||
}
|
||||
}
|
||||
|
||||
if result := object.CheckVerificationCode(checkDest, code, c.GetAcceptLanguage()); result.Code != object.VerificationSuccess {
|
||||
result, err := object.CheckVerificationCode(checkDest, code, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(c.T(err.Error()))
|
||||
return
|
||||
}
|
||||
if result.Code != object.VerificationSuccess {
|
||||
c.ResponseError(result.Msg)
|
||||
return
|
||||
}
|
||||
@ -425,16 +515,22 @@ func (c *ApiController) VerifyCode() {
|
||||
}
|
||||
}
|
||||
|
||||
if result := object.CheckVerificationCode(checkDest, authForm.Code, c.GetAcceptLanguage()); result.Code != object.VerificationSuccess {
|
||||
result, err := object.CheckVerificationCode(checkDest, authForm.Code, c.GetAcceptLanguage())
|
||||
if err != nil {
|
||||
c.ResponseError(c.T(err.Error()))
|
||||
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.ResponseOk()
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ func GetCredManager(passwordType string) CredManager {
|
||||
return NewPlainCredManager()
|
||||
} else if passwordType == "salt" {
|
||||
return NewSha256SaltCredManager()
|
||||
} else if passwordType == "sha512-salt" {
|
||||
return NewSha512SaltCredManager()
|
||||
} else if passwordType == "md5-salt" {
|
||||
return NewMd5UserSaltCredManager()
|
||||
} else if passwordType == "bcrypt" {
|
||||
|
50
cred/sha512-salt.go
Normal file
50
cred/sha512-salt.go
Normal file
@ -0,0 +1,50 @@
|
||||
// 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 cred
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
type Sha512SaltCredManager struct{}
|
||||
|
||||
func getSha512(data []byte) []byte {
|
||||
hash := sha512.Sum512(data)
|
||||
return hash[:]
|
||||
}
|
||||
|
||||
func getSha512HexDigest(s string) string {
|
||||
b := getSha512([]byte(s))
|
||||
res := hex.EncodeToString(b)
|
||||
return res
|
||||
}
|
||||
|
||||
func NewSha512SaltCredManager() *Sha512SaltCredManager {
|
||||
cm := &Sha512SaltCredManager{}
|
||||
return cm
|
||||
}
|
||||
|
||||
func (cm *Sha512SaltCredManager) GetHashedPassword(password string, userSalt string, organizationSalt string) string {
|
||||
res := getSha512HexDigest(password)
|
||||
if organizationSalt != "" {
|
||||
res = getSha512HexDigest(res + organizationSalt)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (cm *Sha512SaltCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, userSalt string, organizationSalt string) bool {
|
||||
return hashedPwd == cm.GetHashedPassword(plainPwd, userSalt, organizationSalt)
|
||||
}
|
@ -27,7 +27,10 @@ import (
|
||||
)
|
||||
|
||||
func deployStaticFiles(provider *object.Provider) {
|
||||
storageProvider := storage.GetStorageProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.RegionId, provider.Bucket, provider.Endpoint)
|
||||
storageProvider, err := storage.GetStorageProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.RegionId, provider.Bucket, provider.Endpoint)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if storageProvider == nil {
|
||||
panic(fmt.Sprintf("the provider type: %s is not supported", provider.Type))
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ func GetEmailProvider(typ string, clientId string, clientSecret string, host str
|
||||
return NewAzureACSEmailProvider(clientSecret, host)
|
||||
} else if typ == "Custom HTTP Email" {
|
||||
return NewHttpEmailProvider(endpoint, method)
|
||||
} else if typ == "SendGrid" {
|
||||
return NewSendgridEmailProvider(clientSecret)
|
||||
} else {
|
||||
return NewSmtpEmailProvider(clientId, clientSecret, host, port, typ, disableSsl)
|
||||
}
|
||||
|
37
email/sendgrid.go
Normal file
37
email/sendgrid.go
Normal file
@ -0,0 +1,37 @@
|
||||
// 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 (
|
||||
"github.com/sendgrid/sendgrid-go"
|
||||
"github.com/sendgrid/sendgrid-go/helpers/mail"
|
||||
)
|
||||
|
||||
type SendgridEmailProvider struct {
|
||||
ApiKey string
|
||||
}
|
||||
|
||||
func NewSendgridEmailProvider(apiKey string) *SendgridEmailProvider {
|
||||
return &SendgridEmailProvider{ApiKey: apiKey}
|
||||
}
|
||||
|
||||
func (s *SendgridEmailProvider) Send(fromAddress string, fromName, toAddress string, subject string, content string) error {
|
||||
from := mail.NewEmail(fromName, fromAddress)
|
||||
to := mail.NewEmail("", toAddress)
|
||||
message := mail.NewSingleEmail(from, subject, to, "", content)
|
||||
client := sendgrid.NewSendClient(s.ApiKey)
|
||||
_, err := client.Send(message)
|
||||
return err
|
||||
}
|
@ -61,6 +61,8 @@ type AuthForm struct {
|
||||
|
||||
Plan string `json:"plan"`
|
||||
Pricing string `json:"pricing"`
|
||||
|
||||
FaceId []float64 `json:"faceId"`
|
||||
}
|
||||
|
||||
func GetAuthFormFieldValue(form *AuthForm, fieldName string) (bool, string) {
|
||||
|
21
go.mod
21
go.mod
@ -9,12 +9,12 @@ require (
|
||||
github.com/beego/beego v1.12.12
|
||||
github.com/beevik/etree v1.1.0
|
||||
github.com/casbin/casbin/v2 v2.77.2
|
||||
github.com/casdoor/go-sms-sender v0.19.0
|
||||
github.com/casdoor/go-sms-sender v0.20.0
|
||||
github.com/casdoor/gomail/v2 v2.0.1
|
||||
github.com/casdoor/notify v0.45.0
|
||||
github.com/casdoor/oss v1.5.0
|
||||
github.com/casdoor/oss v1.6.0
|
||||
github.com/casdoor/xorm-adapter/v3 v3.1.0
|
||||
github.com/casvisor/casvisor-go-sdk v1.0.3
|
||||
github.com/casvisor/casvisor-go-sdk v1.3.0
|
||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
||||
github.com/denisenkom/go-mssqldb v0.9.0
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect
|
||||
@ -22,7 +22,7 @@ require (
|
||||
github.com/fogleman/gg v1.3.0
|
||||
github.com/forestmgy/ldapserver v1.1.0
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5
|
||||
github.com/go-git/go-git/v5 v5.6.0
|
||||
github.com/go-git/go-git/v5 v5.11.0
|
||||
github.com/go-ldap/ldap/v3 v3.4.6
|
||||
github.com/go-mysql-org/go-mysql v1.7.0
|
||||
github.com/go-pay/gopay v1.5.72
|
||||
@ -32,10 +32,10 @@ require (
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||
github.com/google/uuid v1.4.0
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/lestrrat-go/jwx v1.2.21
|
||||
github.com/lestrrat-go/jwx v1.2.29
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3
|
||||
github.com/markbates/goth v1.78.0
|
||||
github.com/markbates/goth v1.79.0
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/nyaruka/phonenumbers v1.1.5
|
||||
github.com/pquerna/otp v1.4.0
|
||||
@ -45,11 +45,12 @@ require (
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/russellhaering/gosaml2 v0.9.0
|
||||
github.com/russellhaering/goxmldsig v1.2.0
|
||||
github.com/sendgrid/sendgrid-go v3.14.0+incompatible // indirect
|
||||
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/stripe/stripe-go/v74 v74.29.0
|
||||
github.com/tealeg/xlsx v1.0.5
|
||||
github.com/thanhpk/randstr v1.0.4
|
||||
@ -59,9 +60,9 @@ require (
|
||||
github.com/xorm-io/core v0.7.4
|
||||
github.com/xorm-io/xorm v1.1.6
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/crypto v0.14.0
|
||||
golang.org/x/net v0.17.0
|
||||
golang.org/x/oauth2 v0.13.0
|
||||
golang.org/x/crypto v0.21.0
|
||||
golang.org/x/net v0.21.0
|
||||
golang.org/x/oauth2 v0.17.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
|
||||
|
200
go.sum
200
go.sum
@ -14,7 +14,6 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.67.0/go.mod h1:YNan/mUhNZFrYUor0vqrsQ0Ffl7Xtm/ACOy/vsTS858=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
|
||||
@ -920,6 +919,8 @@ cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcP
|
||||
cloud.google.com/go/workflows v1.11.1/go.mod h1:Z+t10G1wF7h8LgdY/EmRcQY8ptBD/nvofaL6FqlET6g=
|
||||
cloud.google.com/go/workflows v1.12.0/go.mod h1:PYhSk2b6DhZ508tj8HXKaBh+OFe+xdl0dHF/tJdzPQM=
|
||||
cloud.google.com/go/workflows v1.12.1/go.mod h1:5A95OhD/edtOhQd/O741NSfIMezNTbCwLM1P1tBRGHM=
|
||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
|
||||
git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc=
|
||||
@ -957,11 +958,12 @@ github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/Masterminds/squirrel v1.5.3 h1:YPpoceAcxuzIljlr5iWpNKaql7hLeG1KLSrhvdHpkZc=
|
||||
github.com/Masterminds/squirrel v1.5.3/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
|
||||
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 h1:ra2OtmuW0AE5csawV4YXMNGNQQXvLRps3z2Z59OPO+I=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20221121042443-a3fd332d56d9 h1:vuu1KBsr6l7XU3CHsWESP/4B1SNd+VZkrgeFZsUXrsY=
|
||||
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20221121042443-a3fd332d56d9/go.mod h1:rjP7sIipbZcagro/6TCk6X0ZeFT2eyudH5+fve/cbBA=
|
||||
github.com/SherClockHolmes/webpush-go v1.2.0 h1:sGv0/ZWCvb1HUH+izLqrb2i68HuqD/0Y+AmGQfyqKJA=
|
||||
@ -971,8 +973,6 @@ github.com/Shopify/sarama v1.30.1/go.mod h1:hGgx05L/DiW8XYBXeJdKIN6V2QUy2H6JqME5
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae/go.mod h1:/cvHQkZ1fst0EmZnA5dFtiQdWCNCFYzb+uE2vqVgvx0=
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
|
||||
github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||
github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY=
|
||||
github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk=
|
||||
@ -1071,7 +1071,7 @@ github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyX
|
||||
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/bwmarrin/discordgo v0.27.1 h1:ib9AIc/dom1E/fSIulrBwnez0CToJE113ZGt4HoliGY=
|
||||
github.com/bwmarrin/discordgo v0.27.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
||||
github.com/casbin/casbin v1.7.0 h1:PuzlE8w0JBg/DhIqnkF1Dewf3z+qmUZMVN07PonvVUQ=
|
||||
@ -1083,18 +1083,18 @@ github.com/casbin/casbin/v2 v2.77.2 h1:yQinn/w9x8AswiwqwtrXz93VU48R1aYTXdHEx4RI3
|
||||
github.com/casbin/casbin/v2 v2.77.2/go.mod h1:mzGx0hYW9/ksOSpw3wNjk3NRAroq5VMFYUQ6G43iGPk=
|
||||
github.com/casdoor/go-reddit/v2 v2.1.0 h1:kIbfdJ7AA7H0uTQ8s0q4GGZqSS5V9wVE74RrXyD9XPs=
|
||||
github.com/casdoor/go-reddit/v2 v2.1.0/go.mod h1:eagkvwlZ4Hcsuc/uQsLHYEulz5jN65SVSwV/AIE7zsc=
|
||||
github.com/casdoor/go-sms-sender v0.19.0 h1:qVz7RLXx8aGgfzLUGvhNe6pbhxDqP2/qNY+XPepfpyQ=
|
||||
github.com/casdoor/go-sms-sender v0.19.0/go.mod h1:cQs7qqohMJBgIVZebOCB8ko09naG1vzFJEH59VNIscs=
|
||||
github.com/casdoor/go-sms-sender v0.20.0 h1:yLbCakV04DzzehhgBklOrSeCFjMwpfKBeemz9b+Y8OM=
|
||||
github.com/casdoor/go-sms-sender v0.20.0/go.mod h1:cQs7qqohMJBgIVZebOCB8ko09naG1vzFJEH59VNIscs=
|
||||
github.com/casdoor/gomail/v2 v2.0.1 h1:J+FG6x80s9e5lBHUn8Sv0Y56mud34KiWih5YdmudR/w=
|
||||
github.com/casdoor/gomail/v2 v2.0.1/go.mod h1:VnGPslEAtpix5FjHisR/WKB1qvZDBaujbikxDe9d+2Q=
|
||||
github.com/casdoor/notify v0.45.0 h1:OlaFvcQFjGOgA4mRx07M8AH1gvb5xNo21mcqrVGlLgk=
|
||||
github.com/casdoor/notify v0.45.0/go.mod h1:wNHQu0tiDROMBIvz0j3Om3Lhd5yZ+AIfnFb8MYb8OLQ=
|
||||
github.com/casdoor/oss v1.5.0 h1:mi1htaXR5fynskDry1S3wk+Dd2nRY1z1pVcnGsqMqP4=
|
||||
github.com/casdoor/oss v1.5.0/go.mod h1:rJAWA0hLhtu94t6IRpotLUkXO1NWMASirywQYaGizJE=
|
||||
github.com/casdoor/oss v1.6.0 h1:IOWrGLJ+VO82qS796eaRnzFPPA1Sn3cotYTi7O/VIlQ=
|
||||
github.com/casdoor/oss v1.6.0/go.mod h1:rJAWA0hLhtu94t6IRpotLUkXO1NWMASirywQYaGizJE=
|
||||
github.com/casdoor/xorm-adapter/v3 v3.1.0 h1:NodWayRtSLVSeCvL9H3Hc61k0G17KhV9IymTCNfh3kk=
|
||||
github.com/casdoor/xorm-adapter/v3 v3.1.0/go.mod h1:4WTcUw+bTgBylGHeGHzTtBvuTXRS23dtwzFLl9tsgFM=
|
||||
github.com/casvisor/casvisor-go-sdk v1.0.3 h1:TKJQWKnhtznEBhzLPEdNsp7nJK2GgdD8JsB0lFPMW7U=
|
||||
github.com/casvisor/casvisor-go-sdk v1.0.3/go.mod h1:frnNtH5GA0wxzAQLyZxxfL0RSsSub9GQPi2Ybe86ocE=
|
||||
github.com/casvisor/casvisor-go-sdk v1.3.0 h1:HVgm2g3lWpNX2wBNidzR743QY4O5kAjLUJ9tS2juO8g=
|
||||
github.com/casvisor/casvisor-go-sdk v1.3.0/go.mod h1:frnNtH5GA0wxzAQLyZxxfL0RSsSub9GQPi2Ybe86ocE=
|
||||
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
|
||||
@ -1115,8 +1115,8 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY=
|
||||
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
|
||||
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
@ -1153,6 +1153,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
||||
github.com/cschomburg/go-pushbullet v0.0.0-20171206132031-67759df45fbb h1:7X9nrm+LNWdxzQOiCjy0G51rNUxbH35IDHCjAMvogyM=
|
||||
github.com/cschomburg/go-pushbullet v0.0.0-20171206132031-67759df45fbb/go.mod h1:RfQ9wji3fjcSEsQ+uFCtIh3+BXgcZum8Kt3JxvzYzlk=
|
||||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
|
||||
github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ=
|
||||
github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
|
||||
@ -1162,9 +1164,9 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f h1:q/DpyjJjZs94bziQ7YkBmIlpqbVP7yw179rnzoNVX1M=
|
||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f/go.mod h1:QGrK8vMWWHQYQ3QU9bw9Y9OPNfxccGzfb41qjvVeXtY=
|
||||
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d h1:1iy2qD6JEhHKKhUOA9IWs7mjco7lnw2qx8FsRI2wirE=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||
github.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D0yGjAk=
|
||||
github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/dghubble/oauth1 v0.7.2 h1:pwcinOZy8z6XkNxvPmUDY52M7RDPxt0Xw1zgZ6Cl5JA=
|
||||
@ -1194,6 +1196,9 @@ github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/elimity-com/scim v0.0.0-20230426070224-941a5eac92f3 h1:+zrUtdBUJpY9qptMaaY3CA3T/lBI2+QqfUbzM2uxJss=
|
||||
github.com/elimity-com/scim v0.0.0-20230426070224-941a5eac92f3/go.mod h1:JkjcmqbLW+khwt2fmBPJFBhx2zGZ8XobRZ+O0VhlwWo=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
@ -1254,15 +1259,15 @@ github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3
|
||||
github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY=
|
||||
github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY=
|
||||
github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY=
|
||||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
||||
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
|
||||
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||
github.com/go-git/go-billy/v5 v5.4.0 h1:Vaw7LaSTRJOUric7pe4vnzBSgyuf2KrLsu2Y4ZpQBDE=
|
||||
github.com/go-git/go-billy/v5 v5.4.0/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlKnXHuzrfjTQ=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
|
||||
github.com/go-git/go-git/v5 v5.6.0 h1:JvBdYfcttd+0kdpuWO7KTu0FYgCf5W0t5VwkWGobaa4=
|
||||
github.com/go-git/go-git/v5 v5.6.0/go.mod h1:6nmJ0tJ3N4noMV1Omv7rC5FG3/o8Cm51TB4CJp7mRmE=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
|
||||
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
|
||||
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
|
||||
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@ -1281,6 +1286,8 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-mysql-org/go-mysql v1.7.0 h1:qE5FTRb3ZeTQmlk3pjE+/m2ravGxxRDrVDTyDe9tvqI=
|
||||
github.com/go-mysql-org/go-mysql v1.7.0/go.mod h1:9cRWLtuXNKhamUPMkrDVzBhaomGvqLRLtBiyjvjc4pk=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
@ -1307,6 +1314,7 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
|
||||
github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
|
||||
@ -1316,9 +1324,9 @@ github.com/go-webauthn/revoke v0.1.6/go.mod h1:TB4wuW4tPlwgF3znujA96F70/YSQXHPPW
|
||||
github.com/go-webauthn/webauthn v0.6.0 h1:uLInMApSvBfP+vEFasNE0rnVPG++fjp7lmAIvNhe+UU=
|
||||
github.com/go-webauthn/webauthn v0.6.0/go.mod h1:7edMRZXwuM6JIVjN68G24Bzt+bPCvTmjiL0j+cAmXtY=
|
||||
github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
|
||||
github.com/goccy/go-json v0.9.6/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
|
||||
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
@ -1429,7 +1437,6 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
@ -1540,8 +1547,6 @@ github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOc
|
||||
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
|
||||
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
|
||||
github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
@ -1555,7 +1560,6 @@ github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/U
|
||||
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc=
|
||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/jinzhu/configor v1.2.1 h1:OKk9dsR8i6HPOCZR8BcMtcEImAFjIhbJFZNyn5GCZko=
|
||||
github.com/jinzhu/configor v1.2.1/go.mod h1:nX89/MOmDba7ZX7GCyU/VIaQ2Ar2aizBl2d3JLF/rDc=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
@ -1612,8 +1616,9 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@ -1627,16 +1632,18 @@ github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ic
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A=
|
||||
github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y=
|
||||
github.com/lestrrat-go/blackmagic v1.0.0 h1:XzdxDbuQTz0RZZEmdU7cnQxUtFUzgCSPq8RCz4BxIi4=
|
||||
github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ=
|
||||
github.com/lestrrat-go/httpcc v1.0.0 h1:FszVC6cKfDvBKcJv646+lkh4GydQg2Z29scgUfkOpYc=
|
||||
github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++0Gf8MBnAvE=
|
||||
github.com/lestrrat-go/iter v1.0.1 h1:q8faalr2dY6o8bV45uwrxq12bRa1ezKrB6oM9FUgN4A=
|
||||
github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc=
|
||||
github.com/lestrrat-go/jwx v1.2.21 h1:n+yG95UMm5ZFsDdvsZmui+bqat4Cj/di4ys6XbgSlE8=
|
||||
github.com/lestrrat-go/jwx v1.2.21/go.mod h1:9cfxnOH7G1gN75CaJP2hKGcxFEx5sPh1abRIA/ZJVh4=
|
||||
github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4=
|
||||
github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k=
|
||||
github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
|
||||
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
|
||||
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
|
||||
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
|
||||
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
|
||||
github.com/lestrrat-go/jwx v1.2.28/go.mod h1:nF+91HEMh/MYFVwKPl5HHsBGMPscqbQb+8IDQdIazP8=
|
||||
github.com/lestrrat-go/jwx v1.2.29 h1:QT0utmUJ4/12rmsVQrJ3u55bycPkKqGYuGT4tyRhxSQ=
|
||||
github.com/lestrrat-go/jwx v1.2.29/go.mod h1:hU8k2l6WF0ncx20uQdOmik/Gjg6E3/wIRtXSNFeZuB8=
|
||||
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
|
||||
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
@ -1657,10 +1664,8 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
|
||||
github.com/mailgun/mailgun-go/v4 v4.11.0/go.mod h1:L9s941Lgk7iB3TgywTPz074pK2Ekkg4kgbnAaAyJ2z8=
|
||||
github.com/markbates/going v1.0.0 h1:DQw0ZP7NbNlFGcKbcE/IVSOAFzScxRtLpd0rLMzLhq0=
|
||||
github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA=
|
||||
github.com/markbates/goth v1.78.0 h1:7VEIFDycJp9deyVv3YraGBPdD0ZYQW93Y3Aw1eVP3BY=
|
||||
github.com/markbates/goth v1.78.0/go.mod h1:X6xdNgpapSENS0O35iTBBcMHoJDQDfI9bJl+APCkYMc=
|
||||
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
||||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||
github.com/markbates/goth v1.79.0 h1:fUYi9R6VubVEK2bpmXvIUp7xRcxA68i8ovfUQx/i5Qc=
|
||||
github.com/markbates/goth v1.79.0/go.mod h1:RBD+tcFnXul2NnYuODhnIweOcuVPkBohLfEvutPekcU=
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU=
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
@ -1747,6 +1752,19 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
|
||||
github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
|
||||
github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0=
|
||||
github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
|
||||
github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw=
|
||||
github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
|
||||
github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc=
|
||||
github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk=
|
||||
github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo=
|
||||
github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
|
||||
github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
@ -1754,8 +1772,21 @@ github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
|
||||
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
|
||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||
github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
|
||||
github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc=
|
||||
github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM=
|
||||
github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
|
||||
github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
|
||||
github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
|
||||
github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw=
|
||||
github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw=
|
||||
github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ=
|
||||
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
||||
github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4=
|
||||
github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ=
|
||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
|
||||
@ -1848,12 +1879,15 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
||||
@ -1873,8 +1907,11 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh
|
||||
github.com/scim2/filter-parser/v2 v2.2.0 h1:QGadEcsmypxg8gYChRSM2j1edLyE/2j72j+hdmI4BJM=
|
||||
github.com/scim2/filter-parser/v2 v2.2.0/go.mod h1:jWnkDToqX/Y0ugz0P5VvpVEUKcWcyHHj+X+je9ce5JA=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sendgrid/rest v2.6.9+incompatible h1:1EyIcsNdn9KIisLW50MKwmSRSK+ekueiEMJ7NEoxJo0=
|
||||
github.com/sendgrid/rest v2.6.9+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE=
|
||||
github.com/sendgrid/sendgrid-go v3.13.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8=
|
||||
github.com/sendgrid/sendgrid-go v3.14.0+incompatible h1:KDSasSTktAqMJCYClHVE94Fcif2i7P7wzISv1sU6DUA=
|
||||
github.com/sendgrid/sendgrid-go v3.14.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
|
||||
@ -1902,8 +1939,8 @@ github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0=
|
||||
github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag=
|
||||
github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
|
||||
github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/slack-go/slack v0.12.3 h1:92/dfFU8Q5XP6Wp5rr5/T5JHLM5c5Smtn53fhToAP88=
|
||||
@ -1935,8 +1972,9 @@ github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5J
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
@ -1948,8 +1986,9 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stripe/stripe-go/v74 v74.29.0 h1:ffJ+1Ta1Ccg7yDDz+SfjixX0KizEEJ/wNVRoFYkdwFY=
|
||||
github.com/stripe/stripe-go/v74 v74.29.0/go.mod h1:f9L6LvaXa35ja7eyvP6GQswoaIPaBRvGAimAO+udbBw=
|
||||
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
||||
@ -2101,15 +2140,13 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
@ -2117,8 +2154,12 @@ golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@ -2176,14 +2217,16 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20171115151908-9dfe39835686/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -2221,7 +2264,6 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
@ -2268,9 +2310,12 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@ -2303,8 +2348,9 @@ golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4
|
||||
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
|
||||
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
|
||||
golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk=
|
||||
golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY=
|
||||
golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=
|
||||
golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ=
|
||||
golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA=
|
||||
golang.org/x/sync v0.0.0-20171101214715-fd80eb99c8f6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -2420,8 +2466,10 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@ -2447,8 +2495,11 @@ golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@ -2465,8 +2516,11 @@ golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@ -2486,8 +2540,9 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@ -2547,7 +2602,6 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
@ -2564,15 +2618,19 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
||||
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
|
||||
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
|
||||
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
|
||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@ -2606,7 +2664,6 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.32.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
@ -2665,8 +2722,9 @@ google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
@ -2698,7 +2756,6 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200929141702-51c3e5b607fe/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
@ -2869,7 +2926,6 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
@ -2924,8 +2980,9 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
@ -2968,7 +3025,6 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||
"Email already exists": "Email already exists",
|
||||
"Email cannot be empty": "Email cannot be empty",
|
||||
"Email is invalid": "Email is invalid",
|
||||
"Empty username.": "Empty username.",
|
||||
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
|
||||
"Face data mismatch": "Face data mismatch",
|
||||
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Username already exists",
|
||||
"Username cannot be an email address": "Username cannot be an email address",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Missing parameter",
|
||||
"Please login first": "Please login first",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "The %s is immutable.",
|
||||
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Invalid application id",
|
||||
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||
"Invalid client_id": "Invalid client_id",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Unknown type",
|
||||
"Wrong verification code!": "Wrong verification code!",
|
||||
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "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 provider: %s is not enabled for the application": "Der Anbieter: %s ist nicht für die Anwendung aktiviert",
|
||||
"Unauthorized operation": "Nicht autorisierte Operation",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Unbekannter Authentifizierungstyp (nicht Passwort oder Anbieter), Formular = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Zugehörigkeit darf nicht leer sein",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "Anzeigename kann nicht leer sein",
|
||||
"DisplayName is not valid real name": "DisplayName ist kein gültiger Vorname",
|
||||
"Email already exists": "E-Mail existiert bereits",
|
||||
"Email cannot be empty": "E-Mail darf nicht leer sein",
|
||||
"Email is invalid": "E-Mail ist ungültig",
|
||||
"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",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "Dem Benutzer ist der Zugang verboten, bitte kontaktieren Sie den Administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Der Benutzername darf nur alphanumerische Zeichen, Unterstriche oder Bindestriche enthalten, keine aufeinanderfolgenden Bindestriche oder Unterstriche haben und darf nicht mit einem Bindestrich oder Unterstrich beginnen oder enden.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Benutzername existiert bereits",
|
||||
"Username cannot be an email address": "Benutzername kann keine E-Mail-Adresse sein",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Fehlender Parameter",
|
||||
"Please login first": "Bitte zuerst einloggen",
|
||||
"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",
|
||||
"don't support captchaProvider: ": "Unterstütze captchaProvider nicht:",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "Das %s ist unveränderlich.",
|
||||
"Unknown modify rule %s.": "Unbekannte Änderungsregel %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Ungültige Anwendungs-ID",
|
||||
"the provider: %s does not exist": "Der Anbieter %s existiert nicht"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "Der Anbieter-Typ %s wird nicht unterstützt"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "Leerer clientId oder clientSecret",
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s wird von dieser Anwendung nicht unterstützt",
|
||||
"Invalid application or wrong clientSecret": "Ungültige Anwendung oder falsches clientSecret",
|
||||
"Invalid client_id": "Ungültige client_id",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Unbekannter Typ",
|
||||
"Wrong verification code!": "Falscher Bestätigungscode!",
|
||||
"You should verify your code in %d min!": "Du solltest deinen Code in %d Minuten verifizieren!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "Der Benutzer existiert nicht, bitte zuerst anmelden"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||
"Email already exists": "Email already exists",
|
||||
"Email cannot be empty": "Email cannot be empty",
|
||||
"Email is invalid": "Email is invalid",
|
||||
"Empty username.": "Empty username.",
|
||||
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
|
||||
"Face data mismatch": "Face data mismatch",
|
||||
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Username already exists",
|
||||
"Username cannot be an email address": "Username cannot be an email address",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Missing parameter",
|
||||
"Please login first": "Please login first",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "The %s is immutable.",
|
||||
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Invalid application id",
|
||||
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||
"Invalid client_id": "Invalid client_id",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Unknown type",
|
||||
"Wrong verification code!": "Wrong verification code!",
|
||||
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "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 provider: %s is not enabled for the application": "El proveedor: %s no está habilitado para la aplicación",
|
||||
"Unauthorized operation": "Operación no autorizada",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Tipo de autenticación desconocido (no es contraseña o proveedor), formulario = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Afiliación no puede estar en blanco",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "El nombre de visualización no puede estar en blanco",
|
||||
"DisplayName is not valid real name": "El nombre de pantalla no es un nombre real válido",
|
||||
"Email already exists": "El correo electrónico ya existe",
|
||||
"Email cannot be empty": "El correo electrónico no puede estar vacío",
|
||||
"Email is invalid": "El correo electrónico no es válido",
|
||||
"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",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "El usuario no está autorizado a iniciar sesión, por favor contacte al administrador",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "El nombre de usuario solo puede contener caracteres alfanuméricos, guiones bajos o guiones, no puede tener guiones o subrayados consecutivos, y no puede comenzar ni terminar con un guión o subrayado.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "El nombre de usuario ya existe",
|
||||
"Username cannot be an email address": "Nombre de usuario no puede ser una dirección de correo electrónico",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Parámetro faltante",
|
||||
"Please login first": "Por favor, inicia sesión primero",
|
||||
"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",
|
||||
"don't support captchaProvider: ": "No apoyo a captchaProvider",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "El %s es inmutable.",
|
||||
"Unknown modify rule %s.": "Regla de modificación desconocida %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Identificación de aplicación no válida",
|
||||
"the provider: %s does not exist": "El proveedor: %s no existe"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "El tipo de proveedor: %s no es compatible"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "ClienteId o clienteSecret vacío",
|
||||
"Grant_type: %s is not supported in this application": "El tipo de subvención: %s no es compatible con esta aplicación",
|
||||
"Invalid application or wrong clientSecret": "Solicitud inválida o clientSecret incorrecto",
|
||||
"Invalid client_id": "Identificador de cliente no válido",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Tipo desconocido",
|
||||
"Wrong verification code!": "¡Código de verificación incorrecto!",
|
||||
"You should verify your code in %d min!": "¡Deberías verificar tu código en %d minutos!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "El usuario no existe, por favor regístrese primero"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||
"Email already exists": "Email already exists",
|
||||
"Email cannot be empty": "Email cannot be empty",
|
||||
"Email is invalid": "Email is invalid",
|
||||
"Empty username.": "Empty username.",
|
||||
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
|
||||
"Face data mismatch": "Face data mismatch",
|
||||
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Username already exists",
|
||||
"Username cannot be an email address": "Username cannot be an email address",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Missing parameter",
|
||||
"Please login first": "Please login first",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "The %s is immutable.",
|
||||
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Invalid application id",
|
||||
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||
"Invalid client_id": "Invalid client_id",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Unknown type",
|
||||
"Wrong verification code!": "Wrong verification code!",
|
||||
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||
"Email already exists": "Email already exists",
|
||||
"Email cannot be empty": "Email cannot be empty",
|
||||
"Email is invalid": "Email is invalid",
|
||||
"Empty username.": "Empty username.",
|
||||
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
|
||||
"Face data mismatch": "Face data mismatch",
|
||||
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Username already exists",
|
||||
"Username cannot be an email address": "Username cannot be an email address",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Missing parameter",
|
||||
"Please login first": "Please login first",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "The %s is immutable.",
|
||||
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Invalid application id",
|
||||
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||
"Invalid client_id": "Invalid client_id",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Unknown type",
|
||||
"Wrong verification code!": "Wrong verification code!",
|
||||
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "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 provider: %s is not enabled for the application": "Le fournisseur :%s n'est pas activé pour l'application",
|
||||
"Unauthorized operation": "Opération non autorisée",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Type d'authentification inconnu (pas de mot de passe ou de fournisseur), formulaire = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Affiliation ne peut pas être vide",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "Le nom d'affichage ne peut pas être vide",
|
||||
"DisplayName is not valid real name": "DisplayName n'est pas un nom réel valide",
|
||||
"Email already exists": "E-mail déjà existant",
|
||||
"Email cannot be empty": "L'e-mail ne peut pas être vide",
|
||||
"Email is invalid": "L'adresse e-mail est invalide",
|
||||
"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",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "L'utilisateur est interdit de se connecter, veuillez contacter l'administrateur",
|
||||
"The user: %s doesn't exist in LDAP server": "L'utilisateur %s n'existe pas sur le serveur LDAP",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Le nom d'utilisateur ne peut contenir que des caractères alphanumériques, des traits soulignés ou des tirets, ne peut pas avoir de tirets ou de traits soulignés consécutifs et ne peut pas commencer ou se terminer par un tiret ou un trait souligné.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Nom d'utilisateur existe déjà",
|
||||
"Username cannot be an email address": "Nom d'utilisateur ne peut pas être une adresse e-mail",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Paramètre manquant",
|
||||
"Please login first": "Veuillez d'abord vous connecter",
|
||||
"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",
|
||||
"don't support captchaProvider: ": "ne prend pas en charge captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "cette opération n’est pas autorisée en mode démo"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "Le %s est immuable.",
|
||||
"Unknown modify rule %s.": "Règle de modification inconnue %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Identifiant d'application invalide",
|
||||
"the provider: %s does not exist": "Le fournisseur : %s n'existe pas"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "Le type de fournisseur : %s n'est pas pris en charge"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "clientId ou clientSecret vide",
|
||||
"Grant_type: %s is not supported in this application": "Type_de_subvention : %s n'est pas pris en charge dans cette application",
|
||||
"Invalid application or wrong clientSecret": "Application invalide ou clientSecret incorrect",
|
||||
"Invalid client_id": "Identifiant de client invalide",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Type inconnu",
|
||||
"Wrong verification code!": "Mauvais code de vérification !",
|
||||
"You should verify your code in %d min!": "Vous devriez vérifier votre code en %d min !",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "L'utilisateur n'existe pas, veuillez vous inscrire d'abord"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||
"Email already exists": "Email already exists",
|
||||
"Email cannot be empty": "Email cannot be empty",
|
||||
"Email is invalid": "Email is invalid",
|
||||
"Empty username.": "Empty username.",
|
||||
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
|
||||
"Face data mismatch": "Face data mismatch",
|
||||
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Username already exists",
|
||||
"Username cannot be an email address": "Username cannot be an email address",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Missing parameter",
|
||||
"Please login first": "Please login first",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "The %s is immutable.",
|
||||
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Invalid application id",
|
||||
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||
"Invalid client_id": "Invalid client_id",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Unknown type",
|
||||
"Wrong verification code!": "Wrong verification code!",
|
||||
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "Metode login: login dengan kata sandi tidak diaktifkan untuk aplikasi tersebut",
|
||||
"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",
|
||||
"Unauthorized operation": "Operasi tidak sah",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Jenis otentikasi tidak diketahui (bukan kata sandi atau pemberi), formulir = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Keterkaitan tidak boleh kosong",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "Nama Pengguna tidak boleh kosong",
|
||||
"DisplayName is not valid real name": "DisplayName bukanlah nama asli yang valid",
|
||||
"Email already exists": "Email sudah ada",
|
||||
"Email cannot be empty": "Email tidak boleh kosong",
|
||||
"Email is invalid": "Email tidak valid",
|
||||
"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",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "Pengguna dilarang masuk, silakan hubungi administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Nama pengguna hanya bisa menggunakan karakter alfanumerik, garis bawah atau tanda hubung, tidak boleh memiliki dua tanda hubung atau garis bawah berurutan, dan tidak boleh diawali atau diakhiri dengan tanda hubung atau garis bawah.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Nama pengguna sudah ada",
|
||||
"Username cannot be an email address": "Username tidak bisa menjadi alamat email",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Parameter hilang",
|
||||
"Please login first": "Silahkan login terlebih dahulu",
|
||||
"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",
|
||||
"don't support captchaProvider: ": "Jangan mendukung captchaProvider:",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "%s tidak dapat diubah.",
|
||||
"Unknown modify rule %s.": "Aturan modifikasi tidak diketahui %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "ID aplikasi tidak valid",
|
||||
"the provider: %s does not exist": "provider: %s tidak ada"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "Jenis penyedia: %s tidak didukung"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "Kosong clientId atau clientSecret",
|
||||
"Grant_type: %s is not supported in this application": "Jenis grant (grant_type) %s tidak didukung dalam aplikasi ini",
|
||||
"Invalid application or wrong clientSecret": "Aplikasi tidak valid atau clientSecret salah",
|
||||
"Invalid client_id": "Invalid client_id = ID klien tidak valid",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Tipe tidak diketahui",
|
||||
"Wrong verification code!": "Kode verifikasi salah!",
|
||||
"You should verify your code in %d min!": "Anda harus memverifikasi kode Anda dalam %d menit!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "Pengguna tidak ada, silakan daftar terlebih dahulu"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||
"Email already exists": "Email already exists",
|
||||
"Email cannot be empty": "Email cannot be empty",
|
||||
"Email is invalid": "Email is invalid",
|
||||
"Empty username.": "Empty username.",
|
||||
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
|
||||
"Face data mismatch": "Face data mismatch",
|
||||
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Username already exists",
|
||||
"Username cannot be an email address": "Username cannot be an email address",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Missing parameter",
|
||||
"Please login first": "Please login first",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "The %s is immutable.",
|
||||
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Invalid application id",
|
||||
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||
"Invalid client_id": "Invalid client_id",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Unknown type",
|
||||
"Wrong verification code!": "Wrong verification code!",
|
||||
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "ログイン方法:パスワードでのログインはアプリケーションで有効になっていません",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "プロバイダー:%sはアプリケーションでは有効化されていません",
|
||||
"Unauthorized operation": "不正操作",
|
||||
"Unknown authentication type (not password or provider), form = %s": "不明な認証タイプ(パスワードまたはプロバイダーではない)フォーム=%s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "所属は空白にできません",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "表示名は空白にできません",
|
||||
"DisplayName is not valid real name": "表示名は有効な実名ではありません",
|
||||
"Email already exists": "メールは既に存在します",
|
||||
"Email cannot be empty": "メールが空白にできません",
|
||||
"Email is invalid": "電子メールは無効です",
|
||||
"Empty username.": "空のユーザー名。",
|
||||
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
|
||||
"Face data mismatch": "Face data mismatch",
|
||||
"FirstName cannot be blank": "ファーストネームは空白にできません",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "ユーザーはサインインできません。管理者に連絡してください",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "ユーザー名には英数字、アンダースコア、ハイフンしか含めることができません。連続したハイフンまたはアンダースコアは不可であり、ハイフンまたはアンダースコアで始まるまたは終わることもできません。",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "ユーザー名はすでに存在しています",
|
||||
"Username cannot be an email address": "ユーザー名には電子メールアドレスを使用できません",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "不足しているパラメーター",
|
||||
"Please login first": "最初にログインしてください",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "そのユーザー:%sは存在しません",
|
||||
"don't support captchaProvider: ": "captchaProviderをサポートしないでください",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "%sは不変です。",
|
||||
"Unknown modify rule %s.": "未知の変更ルール%s。"
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "アプリケーションIDが無効です",
|
||||
"the provider: %s does not exist": "プロバイダー%sは存在しません"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "プロバイダータイプ:%sはサポートされていません"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "クライアントIDまたはクライアントシークレットが空です",
|
||||
"Grant_type: %s is not supported in this application": "grant_type:%sはこのアプリケーションでサポートされていません",
|
||||
"Invalid application or wrong clientSecret": "無効なアプリケーションまたは誤ったクライアントシークレットです",
|
||||
"Invalid client_id": "client_idが無効です",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "不明なタイプ",
|
||||
"Wrong verification code!": "誤った検証コードです!",
|
||||
"You should verify your code in %d min!": "あなたは%d分であなたのコードを確認する必要があります!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "ユーザーは存在しません。まず登録してください"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||
"Email already exists": "Email already exists",
|
||||
"Email cannot be empty": "Email cannot be empty",
|
||||
"Email is invalid": "Email is invalid",
|
||||
"Empty username.": "Empty username.",
|
||||
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
|
||||
"Face data mismatch": "Face data mismatch",
|
||||
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Username already exists",
|
||||
"Username cannot be an email address": "Username cannot be an email address",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Missing parameter",
|
||||
"Please login first": "Please login first",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "The %s is immutable.",
|
||||
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Invalid application id",
|
||||
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||
"Invalid client_id": "Invalid client_id",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Unknown type",
|
||||
"Wrong verification code!": "Wrong verification code!",
|
||||
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "어플리케이션에서는 암호를 사용한 로그인 방법이 활성화되어 있지 않습니다",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "제공자 %s은(는) 응용 프로그램에서 활성화되어 있지 않습니다",
|
||||
"Unauthorized operation": "무단 조작",
|
||||
"Unknown authentication type (not password or provider), form = %s": "알 수 없는 인증 유형(암호 또는 공급자가 아님), 폼 = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "소속은 비워 둘 수 없습니다",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "DisplayName는 비어 있을 수 없습니다",
|
||||
"DisplayName is not valid real name": "DisplayName는 유효한 실제 이름이 아닙니다",
|
||||
"Email already exists": "이메일이 이미 존재합니다",
|
||||
"Email cannot be empty": "이메일은 비어 있을 수 없습니다",
|
||||
"Email is invalid": "이메일이 유효하지 않습니다",
|
||||
"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": "이름은 공백일 수 없습니다",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "사용자는 로그인이 금지되어 있습니다. 관리자에게 문의하십시오",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "사용자 이름은 알파벳, 숫자, 밑줄 또는 하이픈만 포함할 수 있으며, 연속된 하이픈 또는 밑줄을 가질 수 없으며, 하이픈 또는 밑줄로 시작하거나 끝날 수 없습니다.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "사용자 이름이 이미 존재합니다",
|
||||
"Username cannot be an email address": "사용자 이름은 이메일 주소가 될 수 없습니다",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "누락된 매개변수",
|
||||
"Please login first": "먼저 로그인 하십시오",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "사용자 %s는 존재하지 않습니다",
|
||||
"don't support captchaProvider: ": "CaptchaProvider를 지원하지 마세요",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "%s 는 변경할 수 없습니다.",
|
||||
"Unknown modify rule %s.": "미확인 수정 규칙 %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "잘못된 애플리케이션 ID입니다",
|
||||
"the provider: %s does not exist": "제공자 %s가 존재하지 않습니다"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "제공자 유형: %s은/는 지원되지 않습니다"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "클라이언트 ID 또는 클라이언트 비밀번호가 비어 있습니다",
|
||||
"Grant_type: %s is not supported in this application": "그랜트 유형: %s은(는) 이 어플리케이션에서 지원되지 않습니다",
|
||||
"Invalid application or wrong clientSecret": "잘못된 어플리케이션 또는 올바르지 않은 클라이언트 시크릿입니다",
|
||||
"Invalid client_id": "잘못된 클라이언트 ID입니다",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "알 수 없는 유형",
|
||||
"Wrong verification code!": "잘못된 인증 코드입니다!",
|
||||
"You should verify your code in %d min!": "당신은 %d분 안에 코드를 검증해야 합니다!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "사용자가 존재하지 않습니다. 먼저 회원 가입 해주세요"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||
"Email already exists": "Email already exists",
|
||||
"Email cannot be empty": "Email cannot be empty",
|
||||
"Email is invalid": "Email is invalid",
|
||||
"Empty username.": "Empty username.",
|
||||
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
|
||||
"Face data mismatch": "Face data mismatch",
|
||||
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Username already exists",
|
||||
"Username cannot be an email address": "Username cannot be an email address",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Missing parameter",
|
||||
"Please login first": "Please login first",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "The %s is immutable.",
|
||||
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Invalid application id",
|
||||
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||
"Invalid client_id": "Invalid client_id",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Unknown type",
|
||||
"Wrong verification code!": "Wrong verification code!",
|
||||
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||
"Email already exists": "Email already exists",
|
||||
"Email cannot be empty": "Email cannot be empty",
|
||||
"Email is invalid": "Email is invalid",
|
||||
"Empty username.": "Empty username.",
|
||||
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
|
||||
"Face data mismatch": "Face data mismatch",
|
||||
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Username already exists",
|
||||
"Username cannot be an email address": "Username cannot be an email address",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Missing parameter",
|
||||
"Please login first": "Please login first",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "The %s is immutable.",
|
||||
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Invalid application id",
|
||||
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||
"Invalid client_id": "Invalid client_id",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Unknown type",
|
||||
"Wrong verification code!": "Wrong verification code!",
|
||||
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||
"Email already exists": "Email already exists",
|
||||
"Email cannot be empty": "Email cannot be empty",
|
||||
"Email is invalid": "Email is invalid",
|
||||
"Empty username.": "Empty username.",
|
||||
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
|
||||
"Face data mismatch": "Face data mismatch",
|
||||
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Username already exists",
|
||||
"Username cannot be an email address": "Username cannot be an email address",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Missing parameter",
|
||||
"Please login first": "Please login first",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "The %s is immutable.",
|
||||
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Invalid application id",
|
||||
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||
"Invalid client_id": "Invalid client_id",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Unknown type",
|
||||
"Wrong verification code!": "Wrong verification code!",
|
||||
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||
"Email already exists": "Email already exists",
|
||||
"Email cannot be empty": "Email cannot be empty",
|
||||
"Email is invalid": "Email is invalid",
|
||||
"Empty username.": "Empty username.",
|
||||
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
|
||||
"Face data mismatch": "Face data mismatch",
|
||||
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Username already exists",
|
||||
"Username cannot be an email address": "Username cannot be an email address",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Missing parameter",
|
||||
"Please login first": "Please login first",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "O %s é imutável.",
|
||||
"Unknown modify rule %s.": "Regra de modificação %s desconhecida."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Id do aplicativo inválido",
|
||||
"the provider: %s does not exist": "o provedor: %s não existe"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "ClientId ou clientSecret vazio",
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||
"Invalid application or wrong clientSecret": "Aplicativo inválido ou clientSecret errado",
|
||||
"Invalid client_id": "client_id inválido",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Unknown type",
|
||||
"Wrong verification code!": "Wrong verification code!",
|
||||
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "Метод входа: вход с паролем не включен для приложения",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "Провайдер: %s не включен для приложения",
|
||||
"Unauthorized operation": "Несанкционированная операция",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Неизвестный тип аутентификации (не пароль и не провайдер), форма = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Принадлежность не может быть пустым значением",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "Имя отображения не может быть пустым",
|
||||
"DisplayName is not valid real name": "DisplayName не является действительным именем",
|
||||
"Email already exists": "Электронная почта уже существует",
|
||||
"Email cannot be empty": "Электронная почта не может быть пустой",
|
||||
"Email is invalid": "Адрес электронной почты недействительный",
|
||||
"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": "Имя не может быть пустым",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "Пользователю запрещен вход, пожалуйста, обратитесь к администратору",
|
||||
"The user: %s doesn't exist in LDAP server": "Пользователь %s не существует на LDAP сервере",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Имя пользователя может состоять только из буквенно-цифровых символов, нижних подчеркиваний или дефисов, не может содержать последовательные дефисы или подчеркивания, а также не может начинаться или заканчиваться на дефис или подчеркивание.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Имя пользователя уже существует",
|
||||
"Username cannot be an email address": "Имя пользователя не может быть адресом электронной почты",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Отсутствующий параметр",
|
||||
"Please login first": "Пожалуйста, сначала войдите в систему",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "Пользователь %s не существует",
|
||||
"don't support captchaProvider: ": "неподдерживаемый captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "эта операция не разрешена в демо-режиме"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "%s неизменяемый.",
|
||||
"Unknown modify rule %s.": "Неизвестное изменение правила %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Неверный идентификатор приложения",
|
||||
"the provider: %s does not exist": "провайдер: %s не существует"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "Тип провайдера: %s не поддерживается"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "Пустой идентификатор клиента или секрет клиента",
|
||||
"Grant_type: %s is not supported in this application": "Тип предоставления: %s не поддерживается в данном приложении",
|
||||
"Invalid application or wrong clientSecret": "Недействительное приложение или неправильный clientSecret",
|
||||
"Invalid client_id": "Недействительный идентификатор клиента",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Неизвестный тип",
|
||||
"Wrong verification code!": "Неправильный код подтверждения!",
|
||||
"You should verify your code in %d min!": "Вы должны проверить свой код через %d минут!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "Пользователь не существует, пожалуйста, сначала зарегистрируйтесь"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||
"Email already exists": "Email already exists",
|
||||
"Email cannot be empty": "Email cannot be empty",
|
||||
"Email is invalid": "Email is invalid",
|
||||
"Empty username.": "Empty username.",
|
||||
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
|
||||
"Face data mismatch": "Face data mismatch",
|
||||
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Username already exists",
|
||||
"Username cannot be an email address": "Username cannot be an email address",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Missing parameter",
|
||||
"Please login first": "Please login first",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "The %s is immutable.",
|
||||
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Invalid application id",
|
||||
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||
"Invalid client_id": "Invalid client_id",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Unknown type",
|
||||
"Wrong verification code!": "Wrong verification code!",
|
||||
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||
"Email already exists": "Email already exists",
|
||||
"Email cannot be empty": "Email cannot be empty",
|
||||
"Email is invalid": "Email is invalid",
|
||||
"Empty username.": "Empty username.",
|
||||
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
|
||||
"Face data mismatch": "Face data mismatch",
|
||||
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Kullanıcı adı zaten var",
|
||||
"Username cannot be an email address": "Kullanıcı adı bir e-mail adresi olamaz",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Missing parameter",
|
||||
"Please login first": "Please login first",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "The %s is immutable.",
|
||||
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Invalid application id",
|
||||
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||
"Invalid client_id": "Invalid client_id",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Unknown type",
|
||||
"Wrong verification code!": "Wrong verification code!",
|
||||
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
|
||||
"The organization: %s does not exist": "The organization: %s does not exist",
|
||||
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
|
||||
"Unauthorized operation": "Unauthorized operation",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||
"DisplayName is not valid real name": "DisplayName is not valid real name",
|
||||
"Email already exists": "Email already exists",
|
||||
"Email cannot be empty": "Email cannot be empty",
|
||||
"Email is invalid": "Email is invalid",
|
||||
"Empty username.": "Empty username.",
|
||||
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
|
||||
"Face data mismatch": "Face data mismatch",
|
||||
"FirstName cannot be blank": "FirstName cannot be blank",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Username already exists",
|
||||
"Username cannot be an email address": "Username cannot be an email address",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Missing parameter",
|
||||
"Please login first": "Please login first",
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "The user: %s doesn't exist",
|
||||
"don't support captchaProvider: ": "don't support captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "The %s is immutable.",
|
||||
"Unknown modify rule %s.": "Unknown modify rule %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Invalid application id",
|
||||
"the provider: %s does not exist": "the provider: %s does not exist"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "The provider type: %s is not supported"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
|
||||
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
|
||||
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
|
||||
"Invalid client_id": "Invalid client_id",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Unknown type",
|
||||
"Wrong verification code!": "Wrong verification code!",
|
||||
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,7 +18,9 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
|
||||
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
|
||||
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
|
||||
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
|
||||
"The login method: login with password is not enabled for the application": "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 provider: %s is not enabled for the application": "Nhà cung cấp: %s không được kích hoạt cho ứng dụng",
|
||||
"Unauthorized operation": "Hoạt động không được ủy quyền",
|
||||
"Unknown authentication type (not password or provider), form = %s": "Loại xác thực không xác định (không phải mật khẩu hoặc nhà cung cấp), biểu mẫu = %s",
|
||||
@ -30,12 +32,15 @@
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "Tình trạng liên kết không thể để trống",
|
||||
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
|
||||
"DisplayName cannot be blank": "Tên hiển thị không thể để trống",
|
||||
"DisplayName is not valid real name": "DisplayName không phải là tên thật hợp lệ",
|
||||
"Email already exists": "Email đã tồn tại",
|
||||
"Email cannot be empty": "Email không thể để trống",
|
||||
"Email is invalid": "Địa chỉ email không hợp lệ",
|
||||
"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",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code exhausted": "Invitation code exhausted",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "Người dùng bị cấm đăng nhập, vui lòng liên hệ với quản trị viên",
|
||||
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Tên người dùng chỉ có thể chứa các ký tự chữ và số, gạch dưới hoặc gạch ngang, không được có hai ký tự gạch dưới hoặc gạch ngang liền kề và không được bắt đầu hoặc kết thúc bằng dấu gạch dưới hoặc gạch ngang.",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
|
||||
"Username already exists": "Tên đăng nhập đã tồn tại",
|
||||
"Username cannot be an email address": "Tên người dùng không thể là địa chỉ email",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "Thiếu tham số",
|
||||
"Please login first": "Vui lòng đăng nhập trước",
|
||||
"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",
|
||||
"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"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "%s không thể thay đổi được.",
|
||||
"Unknown modify rule %s.": "Quy tắc thay đổi không xác định %s."
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "Sai ID ứng dụng",
|
||||
"the provider: %s does not exist": "Nhà cung cấp: %s không tồn tại"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "Loại nhà cung cấp: %s không được hỗ trợ"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "ClientId hoặc clientSecret trống",
|
||||
"Grant_type: %s is not supported in this application": "Loại cấp phép: %s không được hỗ trợ trong ứng dụng này",
|
||||
"Invalid application or wrong clientSecret": "Đơn đăng ký không hợp lệ hoặc sai clientSecret",
|
||||
"Invalid client_id": "Client_id không hợp lệ",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "Loại không xác định",
|
||||
"Wrong verification code!": "Mã xác thực sai!",
|
||||
"You should verify your code in %d min!": "Bạn nên kiểm tra mã của mình trong %d phút!",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
|
||||
"the user does not exist, please sign up first": "Người dùng không tồn tại, vui lòng đăng ký trước"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -18,28 +18,33 @@
|
||||
"The login method: login with LDAP is not enabled for the application": "该应用禁止采用LDAP登录方式",
|
||||
"The login method: login with SMS is not enabled for the application": "该应用禁止采用短信登录方式",
|
||||
"The login method: login with email is not enabled for the application": "该应用禁止采用邮箱登录方式",
|
||||
"The login method: login with face is not enabled for the application": "该应用禁止采用人脸登录",
|
||||
"The login method: login with password is not enabled for the application": "该应用禁止采用密码登录方式",
|
||||
"The organization: %s does not exist": "组织: %s 不存在",
|
||||
"The provider: %s is not enabled for the application": "该应用的提供商: %s未被启用",
|
||||
"Unauthorized operation": "未授权的操作",
|
||||
"Unknown authentication type (not password or provider), form = %s": "未知的认证类型(非密码或第三方提供商):%s",
|
||||
"User's tag: %s is not listed in the application's tags": "用户的标签: %s不在该应用的标签列表中",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "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 没有激活或正在等待订阅并且应用: %s 没有默认值"
|
||||
},
|
||||
"cas": {
|
||||
"Service %s and %s do not match": "服务%s与%s不匹配"
|
||||
},
|
||||
"check": {
|
||||
"Affiliation cannot be blank": "工作单位不可为空",
|
||||
"Default code does not match the code's matching rules": "邀请码默认值和邀请码规则不匹配",
|
||||
"DisplayName cannot be blank": "显示名称不可为空",
|
||||
"DisplayName is not valid real name": "显示名称必须是真实姓名",
|
||||
"Email already exists": "该邮箱已存在",
|
||||
"Email cannot be empty": "邮箱不可为空",
|
||||
"Email is invalid": "无效邮箱",
|
||||
"Empty username.": "用户名不可为空",
|
||||
"Face data does not exist, cannot log in": "未录入人脸数据,无法登录",
|
||||
"Face data mismatch": "人脸不匹配",
|
||||
"FirstName cannot be blank": "名不可以为空",
|
||||
"Invitation code cannot be blank": "Invitation code cannot be blank",
|
||||
"Invitation code cannot be blank": "邀请码不能为空",
|
||||
"Invitation code exhausted": "邀请码使用次数已耗尽",
|
||||
"Invitation code is invalid": "Invitation code is invalid",
|
||||
"Invitation code is invalid": "邀请码无效",
|
||||
"Invitation code suspended": "邀请码已被禁止使用",
|
||||
"LDAP user name or password incorrect": "LDAP密码错误",
|
||||
"LastName cannot be blank": "姓不可以为空",
|
||||
@ -56,6 +61,7 @@
|
||||
"The user is forbidden to sign in, please contact the administrator": "该用户被禁止登录,请联系管理员",
|
||||
"The user: %s doesn't exist in LDAP server": "用户: %s 在LDAP服务器中未找到",
|
||||
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "用户名只能包含字母数字字符、下划线或连字符,不能有连续的连字符或下划线,也不能以连字符或下划线开头或结尾",
|
||||
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "值 \\\"%s\\\"在账户信息字段\\\"%s\\\" 中与应用的账户项正则表达式不匹配",
|
||||
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "值\\\"%s\\\"在注册字段\\\"%s\\\"中与应用\\\"%s\\\"的注册项正则表达式不匹配",
|
||||
"Username already exists": "用户名已存在",
|
||||
"Username cannot be an email address": "用户名不可以是邮箱地址",
|
||||
@ -72,6 +78,7 @@
|
||||
"general": {
|
||||
"Missing parameter": "缺少参数",
|
||||
"Please login first": "请先登录",
|
||||
"The organization: %s should have one application at least": "组织: %s 应该拥有至少一个应用",
|
||||
"The user: %s doesn't exist": "用户: %s不存在",
|
||||
"don't support captchaProvider: ": "不支持验证码提供商: ",
|
||||
"this operation is not allowed in demo mode": "demo模式下不允许该操作"
|
||||
@ -92,6 +99,9 @@
|
||||
"The %s is immutable.": "%s 是不可变的",
|
||||
"Unknown modify rule %s.": "未知的修改规则: %s"
|
||||
},
|
||||
"permission": {
|
||||
"The permission: \\\"%s\\\" doesn't exist": "权限: \\\"%s\\\" 不存在"
|
||||
},
|
||||
"provider": {
|
||||
"Invalid application id": "无效的应用ID",
|
||||
"the provider: %s does not exist": "提供商: %s不存在"
|
||||
@ -116,7 +126,6 @@
|
||||
"The provider type: %s is not supported": "不支持的提供商类型: %s"
|
||||
},
|
||||
"token": {
|
||||
"Empty clientId or clientSecret": "clientId或clientSecret为空",
|
||||
"Grant_type: %s is not supported in this application": "该应用不支持Grant_type: %s",
|
||||
"Invalid application or wrong clientSecret": "无效应用或错误的clientSecret",
|
||||
"Invalid client_id": "无效的ClientId",
|
||||
@ -145,6 +154,8 @@
|
||||
"Unknown type": "未知类型",
|
||||
"Wrong verification code!": "验证码错误!",
|
||||
"You should verify your code in %d min!": "请在 %d 分钟内输入正确验证码",
|
||||
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "请添加一个SMS提供商到应用: %s 的 \\\"提供商 \\\"列表",
|
||||
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "请添加一个Email提供商到应用: %s 的 \\\"提供商 \\\"列表",
|
||||
"the user does not exist, please sign up first": "用户不存在,请先注册"
|
||||
},
|
||||
"webauthn": {
|
||||
|
@ -121,6 +121,9 @@ func (idp *AdfsIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
return nil, err
|
||||
}
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var respKeys struct {
|
||||
Keys []interface{} `json:"keys"`
|
||||
}
|
||||
|
@ -98,11 +98,19 @@ func (idp *CustomIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
|
||||
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
|
||||
for k, v := range idp.UserMapping {
|
||||
_, ok := dataMap[v]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot find %s in user from castom provider", v)
|
||||
return nil, fmt.Errorf("cannot find %s in user from custom provider", v)
|
||||
}
|
||||
dataMap[k] = dataMap[v]
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ import (
|
||||
"github.com/markbates/goth/providers/twitterv2"
|
||||
"github.com/markbates/goth/providers/typetalk"
|
||||
"github.com/markbates/goth/providers/uber"
|
||||
"github.com/markbates/goth/providers/vk"
|
||||
"github.com/markbates/goth/providers/wepay"
|
||||
"github.com/markbates/goth/providers/xero"
|
||||
"github.com/markbates/goth/providers/yahoo"
|
||||
@ -371,6 +372,11 @@ func NewGothIdProvider(providerType string, clientId string, clientSecret string
|
||||
Provider: uber.New(clientId, clientSecret, redirectUrl),
|
||||
Session: &uber.Session{},
|
||||
}
|
||||
case "VK":
|
||||
idp = GothIdProvider{
|
||||
Provider: vk.New(clientId, clientSecret, redirectUrl),
|
||||
Session: &vk.Session{},
|
||||
}
|
||||
case "Wepay":
|
||||
idp = GothIdProvider{
|
||||
Provider: wepay.New(clientId, clientSecret, redirectUrl),
|
||||
|
104
idp/wechat.go
104
idp/wechat.go
@ -16,25 +16,38 @@ package idp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/skip2/go-qrcode"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
var (
|
||||
WechatCacheMap map[string]WechatCacheMapValue
|
||||
Lock sync.RWMutex
|
||||
)
|
||||
|
||||
type WeChatIdProvider struct {
|
||||
Client *http.Client
|
||||
Config *oauth2.Config
|
||||
}
|
||||
|
||||
type WechatCacheMapValue struct {
|
||||
IsScanned bool
|
||||
WechatUnionId string
|
||||
}
|
||||
|
||||
func NewWeChatIdProvider(clientId string, clientSecret string, redirectUrl string) *WeChatIdProvider {
|
||||
idp := &WeChatIdProvider{}
|
||||
|
||||
@ -77,6 +90,15 @@ type WechatAccessToken struct {
|
||||
// GetToken use code get access_token (*operation of getting code ought to be done in front)
|
||||
// get more detail via: https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
|
||||
func (idp *WeChatIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
if strings.HasPrefix(code, "wechat_oa:") {
|
||||
token := oauth2.Token{
|
||||
AccessToken: code,
|
||||
TokenType: "WeChatAccessToken",
|
||||
Expiry: time.Time{},
|
||||
}
|
||||
return &token, nil
|
||||
}
|
||||
|
||||
params := url.Values{}
|
||||
params.Add("grant_type", "authorization_code")
|
||||
params.Add("appid", idp.Config.ClientID)
|
||||
@ -157,6 +179,29 @@ type WechatUserInfo struct {
|
||||
func (idp *WeChatIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
var wechatUserInfo WechatUserInfo
|
||||
accessToken := token.AccessToken
|
||||
|
||||
if strings.HasPrefix(accessToken, "wechat_oa:") {
|
||||
Lock.RLock()
|
||||
mapValue, ok := WechatCacheMap[accessToken[10:]]
|
||||
Lock.RUnlock()
|
||||
|
||||
if !ok || mapValue.WechatUnionId == "" {
|
||||
return nil, fmt.Errorf("error ticket")
|
||||
}
|
||||
|
||||
Lock.Lock()
|
||||
delete(WechatCacheMap, accessToken[10:])
|
||||
Lock.Unlock()
|
||||
|
||||
userInfo := UserInfo{
|
||||
Id: mapValue.WechatUnionId,
|
||||
Username: "wx_user_" + mapValue.WechatUnionId,
|
||||
DisplayName: "wx_user_" + mapValue.WechatUnionId,
|
||||
AvatarUrl: "",
|
||||
}
|
||||
return &userInfo, nil
|
||||
}
|
||||
|
||||
openid := token.Extra("Openid")
|
||||
|
||||
userInfoUrl := fmt.Sprintf("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s", accessToken, openid)
|
||||
@ -204,60 +249,70 @@ func BuildWechatOpenIdKey(appId string) string {
|
||||
return fmt.Sprintf("wechat_openid_%s", appId)
|
||||
}
|
||||
|
||||
func GetWechatOfficialAccountAccessToken(clientId string, clientSecret string) (string, error) {
|
||||
func GetWechatOfficialAccountAccessToken(clientId string, clientSecret string) (string, string, error) {
|
||||
accessTokenUrl := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", clientId, clientSecret)
|
||||
request, err := http.NewRequest("GET", accessTokenUrl, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
client := new(http.Client)
|
||||
resp, err := client.Do(request)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBytes, err := ioutil.ReadAll(resp.Body)
|
||||
respBytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
var data struct {
|
||||
ExpireIn int `json:"expires_in"`
|
||||
AccessToken string `json:"access_token"`
|
||||
ErrCode int `json:"errcode"`
|
||||
Errmsg string `json:"errmsg"`
|
||||
}
|
||||
err = json.Unmarshal(respBytes, &data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return data.AccessToken, nil
|
||||
return data.AccessToken, data.Errmsg, nil
|
||||
}
|
||||
|
||||
func GetWechatOfficialAccountQRCode(clientId string, clientSecret string) (string, error) {
|
||||
accessToken, err := GetWechatOfficialAccountAccessToken(clientId, clientSecret)
|
||||
func GetWechatOfficialAccountQRCode(clientId string, clientSecret string, providerId string) (string, string, error) {
|
||||
accessToken, errMsg, err := GetWechatOfficialAccountAccessToken(clientId, clientSecret)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
if errMsg != "" {
|
||||
return "", "", fmt.Errorf("Fail to fetch WeChat QRcode: %s", errMsg)
|
||||
}
|
||||
|
||||
client := new(http.Client)
|
||||
|
||||
weChatEndpoint := "https://api.weixin.qq.com/cgi-bin/qrcode/create"
|
||||
qrCodeUrl := fmt.Sprintf("%s?access_token=%s", weChatEndpoint, accessToken)
|
||||
params := `{"action_name": "QR_LIMIT_STR_SCENE", "action_info": {"scene": {"scene_str": "test"}}}`
|
||||
params := fmt.Sprintf(`{"expire_seconds": 3600, "action_name": "QR_STR_SCENE", "action_info": {"scene": {"scene_str": "%s"}}}`, providerId)
|
||||
|
||||
bodyData := bytes.NewReader([]byte(params))
|
||||
requeset, err := http.NewRequest("POST", qrCodeUrl, bodyData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
resp, err := client.Do(requeset)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBytes, err := ioutil.ReadAll(resp.Body)
|
||||
respBytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
var data struct {
|
||||
Ticket string `json:"ticket"`
|
||||
@ -266,11 +321,26 @@ func GetWechatOfficialAccountQRCode(clientId string, clientSecret string) (strin
|
||||
}
|
||||
err = json.Unmarshal(respBytes, &data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
var png []byte
|
||||
png, err = qrcode.Encode(data.URL, qrcode.Medium, 256)
|
||||
base64Image := base64.StdEncoding.EncodeToString(png)
|
||||
return base64Image, nil
|
||||
return base64Image, data.Ticket, nil
|
||||
}
|
||||
|
||||
func VerifyWechatSignature(token string, nonce string, timestamp string, signature string) bool {
|
||||
// verify the signature
|
||||
tmpArr := sort.StringSlice{token, timestamp, nonce}
|
||||
sort.Sort(tmpArr)
|
||||
|
||||
tmpStr := ""
|
||||
for _, str := range tmpArr {
|
||||
tmpStr = tmpStr + str
|
||||
}
|
||||
|
||||
b := sha1.Sum([]byte(tmpStr))
|
||||
res := hex.EncodeToString(b[:])
|
||||
return res == signature
|
||||
}
|
||||
|
@ -8,12 +8,62 @@
|
||||
"favicon": "",
|
||||
"passwordType": "plain",
|
||||
"passwordSalt": "",
|
||||
"passwordOptions": ["AtLeast6"],
|
||||
"countryCodes": ["US", "GB", "ES", "FR", "DE", "CN", "JP", "KR", "VN", "ID", "SG", "IN", "IT", "MY", "TR", "DZ", "IL", "PH", "NL", "PL", "FI", "SE", "UA", "KZ"],
|
||||
"passwordOptions": [
|
||||
"AtLeast6"
|
||||
],
|
||||
"countryCodes": [
|
||||
"US",
|
||||
"GB",
|
||||
"ES",
|
||||
"FR",
|
||||
"DE",
|
||||
"CN",
|
||||
"JP",
|
||||
"KR",
|
||||
"VN",
|
||||
"ID",
|
||||
"SG",
|
||||
"IN",
|
||||
"IT",
|
||||
"MY",
|
||||
"TR",
|
||||
"DZ",
|
||||
"IL",
|
||||
"PH",
|
||||
"NL",
|
||||
"PL",
|
||||
"FI",
|
||||
"SE",
|
||||
"UA",
|
||||
"KZ"
|
||||
],
|
||||
"defaultAvatar": "",
|
||||
"defaultApplication": "",
|
||||
"tags": [],
|
||||
"languages": ["en", "zh", "es", "fr", "de", "id", "ja", "ko", "ru", "vi", "it", "ms", "tr","ar", "he", "nl", "pl", "fi", "sv", "uk", "kk", "fa"],
|
||||
"languages": [
|
||||
"en",
|
||||
"zh",
|
||||
"es",
|
||||
"fr",
|
||||
"de",
|
||||
"id",
|
||||
"ja",
|
||||
"ko",
|
||||
"ru",
|
||||
"vi",
|
||||
"it",
|
||||
"ms",
|
||||
"tr",
|
||||
"ar",
|
||||
"he",
|
||||
"nl",
|
||||
"pl",
|
||||
"fi",
|
||||
"sv",
|
||||
"uk",
|
||||
"kk",
|
||||
"fa"
|
||||
],
|
||||
"masterPassword": "",
|
||||
"defaultPassword": "",
|
||||
"initScore": 2000,
|
||||
@ -49,18 +99,23 @@
|
||||
{
|
||||
"name": "Password",
|
||||
"displayName": "Password",
|
||||
"rule": "All",
|
||||
"rule": "All"
|
||||
},
|
||||
{
|
||||
"name": "Verification code",
|
||||
"displayName": "Verification code",
|
||||
"rule": "All",
|
||||
"rule": "All"
|
||||
},
|
||||
{
|
||||
"name": "WebAuthn",
|
||||
"displayName": "WebAuthn",
|
||||
"rule": "None",
|
||||
"rule": "None"
|
||||
},
|
||||
{
|
||||
"name": "Face ID",
|
||||
"displayName": "Face ID",
|
||||
"rule": "None"
|
||||
}
|
||||
],
|
||||
"signupItems": [
|
||||
{
|
||||
@ -72,55 +127,67 @@
|
||||
},
|
||||
{
|
||||
"name": "Username",
|
||||
"visible": true,
|
||||
"required": true,
|
||||
"prompted": false,
|
||||
"rule": "None"
|
||||
"visible": true,
|
||||
"required": true,
|
||||
"prompted": false,
|
||||
"rule": "None"
|
||||
},
|
||||
{
|
||||
"name": "Display name",
|
||||
"visible": true,
|
||||
"required": true,
|
||||
"prompted": false,
|
||||
"rule": "None"
|
||||
"visible": true,
|
||||
"required": true,
|
||||
"prompted": false,
|
||||
"rule": "None"
|
||||
},
|
||||
{
|
||||
"name": "Password",
|
||||
"visible": true,
|
||||
"required": true,
|
||||
"prompted": false,
|
||||
"rule": "None"
|
||||
"visible": true,
|
||||
"required": true,
|
||||
"prompted": false,
|
||||
"rule": "None"
|
||||
},
|
||||
{
|
||||
"name": "Confirm password",
|
||||
"visible": true,
|
||||
"required": true,
|
||||
"prompted": false,
|
||||
"rule": "None"
|
||||
"visible": true,
|
||||
"required": true,
|
||||
"prompted": false,
|
||||
"rule": "None"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"visible": true,
|
||||
"required": true,
|
||||
"prompted": false,
|
||||
"rule": "None"
|
||||
"visible": true,
|
||||
"required": true,
|
||||
"prompted": false,
|
||||
"rule": "None"
|
||||
},
|
||||
{
|
||||
"name": "Phone",
|
||||
"visible": true,
|
||||
"required": true,
|
||||
"prompted": false,
|
||||
"rule": "None"
|
||||
"visible": true,
|
||||
"required": true,
|
||||
"prompted": false,
|
||||
"rule": "None"
|
||||
},
|
||||
{
|
||||
"name": "Agreement",
|
||||
"visible": true,
|
||||
"required": true,
|
||||
"prompted": false,
|
||||
"rule": "None"
|
||||
"visible": true,
|
||||
"required": true,
|
||||
"prompted": false,
|
||||
"rule": "None"
|
||||
}
|
||||
],
|
||||
"redirectUris": [""],
|
||||
"grantTypes": [
|
||||
"authorization_code",
|
||||
"password",
|
||||
"client_credentials",
|
||||
"token",
|
||||
"id_token",
|
||||
"refresh_token"
|
||||
],
|
||||
"redirectUris": [
|
||||
"http://localhost:9000/callback"
|
||||
],
|
||||
"tokenFormat": "JWT",
|
||||
"tokenFields": [],
|
||||
"expireInHours": 168,
|
||||
"failedSigninLimit": 5,
|
||||
"failedSigninFrozenTime": 15
|
||||
@ -146,7 +213,8 @@
|
||||
"isForbidden": false,
|
||||
"isDeleted": false,
|
||||
"signupApplication": "",
|
||||
"createdIp": ""
|
||||
"createdIp": "",
|
||||
"groups": []
|
||||
}
|
||||
],
|
||||
"providers": [
|
||||
@ -349,5 +417,74 @@
|
||||
"owner": "",
|
||||
"url": ""
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"owner": "",
|
||||
"name": "",
|
||||
"displayName": "",
|
||||
"manager": "",
|
||||
"contactEmail": "",
|
||||
"type": "",
|
||||
"parent_id": "",
|
||||
"isTopGroup": true,
|
||||
"title": "",
|
||||
"key": "",
|
||||
"children": "",
|
||||
"isEnabled": true
|
||||
}
|
||||
],
|
||||
"adapters": [
|
||||
{
|
||||
"owner": "",
|
||||
"name": "",
|
||||
"table": "",
|
||||
"useSameDb": true,
|
||||
"type": "",
|
||||
"databaseType": "",
|
||||
"database": "",
|
||||
"host": "",
|
||||
"port": 0,
|
||||
"user": "",
|
||||
"password": ""
|
||||
}
|
||||
],
|
||||
"enforcers": [
|
||||
{
|
||||
"owner": "",
|
||||
"name": "",
|
||||
"displayName": "",
|
||||
"description": "",
|
||||
"model": "",
|
||||
"adapter": "",
|
||||
"enforcer": ""
|
||||
}
|
||||
],
|
||||
"plans": [
|
||||
{
|
||||
"owner": "",
|
||||
"name": "",
|
||||
"displayName": "",
|
||||
"description": "",
|
||||
"price": 0,
|
||||
"currency": "",
|
||||
"period": "",
|
||||
"product": "",
|
||||
"paymentProviders": [],
|
||||
"isEnabled": true,
|
||||
"role": ""
|
||||
}
|
||||
],
|
||||
"pricings": [
|
||||
{
|
||||
"owner": "",
|
||||
"name": "",
|
||||
"displayName": "",
|
||||
"description": "",
|
||||
"plans": [],
|
||||
"isEnabled": true,
|
||||
"trialDuration": 0,
|
||||
"application": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
|
3
main.go
3
main.go
@ -36,12 +36,12 @@ func main() {
|
||||
object.CreateTables()
|
||||
|
||||
object.InitDb()
|
||||
object.InitFromFile()
|
||||
object.InitDefaultStorageProvider()
|
||||
object.InitLdapAutoSynchronizer()
|
||||
proxy.InitHttpClient()
|
||||
authz.InitApi()
|
||||
object.InitUserManager()
|
||||
object.InitFromFile()
|
||||
object.InitCasvisorConfig()
|
||||
|
||||
util.SafeGoroutine(func() { object.RunSyncUsersJob() })
|
||||
@ -59,6 +59,7 @@ func main() {
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.ApiFilter)
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.PrometheusFilter)
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage)
|
||||
beego.InsertFilter("*", beego.AfterExec, routers.AfterRecordMessage, false)
|
||||
|
||||
beego.BConfig.WebConfig.Session.SessionOn = true
|
||||
beego.BConfig.WebConfig.Session.SessionName = "casdoor_session_id"
|
||||
|
@ -37,7 +37,7 @@ type Adapter struct {
|
||||
Host string `xorm:"varchar(100)" json:"host"`
|
||||
Port int `json:"port"`
|
||||
User string `xorm:"varchar(100)" json:"user"`
|
||||
Password string `xorm:"varchar(100)" json:"password"`
|
||||
Password string `xorm:"varchar(150)" json:"password"`
|
||||
Database string `xorm:"varchar(100)" json:"database"`
|
||||
|
||||
*xormadapter.Adapter `xorm:"-" json:"-"`
|
||||
@ -178,6 +178,7 @@ func (adapter *Adapter) InitAdapter() error {
|
||||
dataSourceName = strings.ReplaceAll(dataSourceName, "dbi.", "db.")
|
||||
}
|
||||
|
||||
dataSourceName = conf.ReplaceDataSourceNameByDocker(dataSourceName)
|
||||
engine, err := xorm.NewEngine(driverName, dataSourceName)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/casdoor/casdoor/idp"
|
||||
"github.com/casdoor/casdoor/i18n"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/xorm-io/core"
|
||||
)
|
||||
@ -41,6 +41,15 @@ type SignupItem struct {
|
||||
Rule string `json:"rule"`
|
||||
}
|
||||
|
||||
type SigninItem struct {
|
||||
Name string `json:"name"`
|
||||
Visible bool `json:"visible"`
|
||||
Label string `json:"label"`
|
||||
Placeholder string `json:"placeholder"`
|
||||
Rule string `json:"rule"`
|
||||
IsCustom bool `json:"isCustom"`
|
||||
}
|
||||
|
||||
type SamlItem struct {
|
||||
Name string `json:"name"`
|
||||
NameFormat string `json:"nameFormat"`
|
||||
@ -52,31 +61,34 @@ type Application struct {
|
||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
Logo string `xorm:"varchar(200)" json:"logo"`
|
||||
HomepageUrl string `xorm:"varchar(100)" json:"homepageUrl"`
|
||||
Description string `xorm:"varchar(100)" json:"description"`
|
||||
Organization string `xorm:"varchar(100)" json:"organization"`
|
||||
Cert string `xorm:"varchar(100)" json:"cert"`
|
||||
EnablePassword bool `json:"enablePassword"`
|
||||
EnableSignUp bool `json:"enableSignUp"`
|
||||
EnableSigninSession bool `json:"enableSigninSession"`
|
||||
EnableAutoSignin bool `json:"enableAutoSignin"`
|
||||
EnableCodeSignin bool `json:"enableCodeSignin"`
|
||||
EnableSamlCompress bool `json:"enableSamlCompress"`
|
||||
EnableSamlC14n10 bool `json:"enableSamlC14n10"`
|
||||
EnableWebAuthn bool `json:"enableWebAuthn"`
|
||||
EnableLinkWithEmail bool `json:"enableLinkWithEmail"`
|
||||
OrgChoiceMode string `json:"orgChoiceMode"`
|
||||
SamlReplyUrl string `xorm:"varchar(100)" json:"samlReplyUrl"`
|
||||
Providers []*ProviderItem `xorm:"mediumtext" json:"providers"`
|
||||
SigninMethods []*SigninMethod `xorm:"varchar(2000)" json:"signinMethods"`
|
||||
SignupItems []*SignupItem `xorm:"varchar(2000)" json:"signupItems"`
|
||||
GrantTypes []string `xorm:"varchar(1000)" json:"grantTypes"`
|
||||
OrganizationObj *Organization `xorm:"-" json:"organizationObj"`
|
||||
CertPublicKey string `xorm:"-" json:"certPublicKey"`
|
||||
Tags []string `xorm:"mediumtext" json:"tags"`
|
||||
SamlAttributes []*SamlItem `xorm:"varchar(1000)" json:"samlAttributes"`
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
Logo string `xorm:"varchar(200)" json:"logo"`
|
||||
HomepageUrl string `xorm:"varchar(100)" json:"homepageUrl"`
|
||||
Description string `xorm:"varchar(100)" json:"description"`
|
||||
Organization string `xorm:"varchar(100)" json:"organization"`
|
||||
Cert string `xorm:"varchar(100)" json:"cert"`
|
||||
HeaderHtml string `xorm:"mediumtext" json:"headerHtml"`
|
||||
EnablePassword bool `json:"enablePassword"`
|
||||
EnableSignUp bool `json:"enableSignUp"`
|
||||
EnableSigninSession bool `json:"enableSigninSession"`
|
||||
EnableAutoSignin bool `json:"enableAutoSignin"`
|
||||
EnableCodeSignin bool `json:"enableCodeSignin"`
|
||||
EnableSamlCompress bool `json:"enableSamlCompress"`
|
||||
EnableSamlC14n10 bool `json:"enableSamlC14n10"`
|
||||
EnableSamlPostBinding bool `json:"enableSamlPostBinding"`
|
||||
EnableWebAuthn bool `json:"enableWebAuthn"`
|
||||
EnableLinkWithEmail bool `json:"enableLinkWithEmail"`
|
||||
OrgChoiceMode string `json:"orgChoiceMode"`
|
||||
SamlReplyUrl string `xorm:"varchar(100)" json:"samlReplyUrl"`
|
||||
Providers []*ProviderItem `xorm:"mediumtext" json:"providers"`
|
||||
SigninMethods []*SigninMethod `xorm:"varchar(2000)" json:"signinMethods"`
|
||||
SignupItems []*SignupItem `xorm:"varchar(2000)" json:"signupItems"`
|
||||
SigninItems []*SigninItem `xorm:"mediumtext" json:"signinItems"`
|
||||
GrantTypes []string `xorm:"varchar(1000)" json:"grantTypes"`
|
||||
OrganizationObj *Organization `xorm:"-" json:"organizationObj"`
|
||||
CertPublicKey string `xorm:"-" json:"certPublicKey"`
|
||||
Tags []string `xorm:"mediumtext" json:"tags"`
|
||||
SamlAttributes []*SamlItem `xorm:"varchar(1000)" json:"samlAttributes"`
|
||||
|
||||
ClientId string `xorm:"varchar(100)" json:"clientId"`
|
||||
ClientSecret string `xorm:"varchar(100)" json:"clientSecret"`
|
||||
@ -93,6 +105,7 @@ type Application struct {
|
||||
SignupHtml string `xorm:"mediumtext" json:"signupHtml"`
|
||||
SigninHtml string `xorm:"mediumtext" json:"signinHtml"`
|
||||
ThemeData *ThemeData `xorm:"json" json:"themeData"`
|
||||
FooterHtml string `xorm:"mediumtext" json:"footerHtml"`
|
||||
FormCss string `xorm:"text" json:"formCss"`
|
||||
FormCssMobile string `xorm:"text" json:"formCssMobile"`
|
||||
FormOffset int `json:"formOffset"`
|
||||
@ -163,15 +176,6 @@ func getProviderMap(owner string) (m map[string]*Provider, err error) {
|
||||
|
||||
m = map[string]*Provider{}
|
||||
for _, provider := range providers {
|
||||
// Get QRCode only once
|
||||
if provider.Type == "WeChat" && provider.DisableSsl && provider.Content == "" {
|
||||
provider.Content, err = idp.GetWechatOfficialAccountQRCode(provider.ClientId2, provider.ClientSecret2)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
UpdateProvider(provider.Owner+"/"+provider.Name, provider)
|
||||
}
|
||||
|
||||
m[provider.Name] = GetMaskedProvider(provider, true)
|
||||
}
|
||||
|
||||
@ -199,6 +203,100 @@ func extendApplicationWithOrg(application *Application) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func extendApplicationWithSigninItems(application *Application) (err error) {
|
||||
if len(application.SigninItems) == 0 {
|
||||
signinItem := &SigninItem{
|
||||
Name: "Back button",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .back-button {\n top: 65px;\n left: 15px;\n position: absolute;\n }\n</style>\n",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
application.SigninItems = append(application.SigninItems, signinItem)
|
||||
signinItem = &SigninItem{
|
||||
Name: "Languages",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .login-languages {\n top: 55px;\n right: 5px;\n position: absolute;\n }\n</style>\n",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
application.SigninItems = append(application.SigninItems, signinItem)
|
||||
signinItem = &SigninItem{
|
||||
Name: "Logo",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .login-logo-box {\n }\n</style>\n",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
application.SigninItems = append(application.SigninItems, signinItem)
|
||||
signinItem = &SigninItem{
|
||||
Name: "Signin methods",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .signin-methods {\n }\n</style>\n",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
application.SigninItems = append(application.SigninItems, signinItem)
|
||||
signinItem = &SigninItem{
|
||||
Name: "Username",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .login-username {\n }\n</style>\n",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
application.SigninItems = append(application.SigninItems, signinItem)
|
||||
signinItem = &SigninItem{
|
||||
Name: "Password",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .login-password {\n }\n</style>\n",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
application.SigninItems = append(application.SigninItems, signinItem)
|
||||
signinItem = &SigninItem{
|
||||
Name: "Agreement",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .login-agreement {\n }\n</style>\n",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
application.SigninItems = append(application.SigninItems, signinItem)
|
||||
signinItem = &SigninItem{
|
||||
Name: "Forgot password?",
|
||||
Visible: true,
|
||||
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: "",
|
||||
Rule: "None",
|
||||
}
|
||||
application.SigninItems = append(application.SigninItems, signinItem)
|
||||
signinItem = &SigninItem{
|
||||
Name: "Login button",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .login-button-box {\n margin-bottom: 5px;\n }\n .login-button {\n width: 100%;\n }\n</style>\n",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
application.SigninItems = append(application.SigninItems, signinItem)
|
||||
signinItem = &SigninItem{
|
||||
Name: "Signup link",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .login-signup-link {\n margin-bottom: 24px;\n display: flex;\n justify-content: end;\n}\n</style>\n",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
application.SigninItems = append(application.SigninItems, signinItem)
|
||||
signinItem = &SigninItem{
|
||||
Name: "Providers",
|
||||
Visible: true,
|
||||
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: "",
|
||||
Rule: "None",
|
||||
}
|
||||
application.SigninItems = append(application.SigninItems, signinItem)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func extendApplicationWithSigninMethods(application *Application) (err error) {
|
||||
if len(application.SigninMethods) == 0 {
|
||||
if application.EnablePassword {
|
||||
@ -213,6 +311,9 @@ func extendApplicationWithSigninMethods(application *Application) (err error) {
|
||||
signinMethod := &SigninMethod{Name: "WebAuthn", DisplayName: "WebAuthn", Rule: "None"}
|
||||
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 {
|
||||
@ -249,6 +350,10 @@ func getApplication(owner string, name string) (*Application, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = extendApplicationWithSigninItems(&application)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &application, nil
|
||||
} else {
|
||||
@ -279,6 +384,11 @@ func GetApplicationByOrganizationName(organization string) (*Application, error)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = extendApplicationWithSigninItems(&application)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &application, nil
|
||||
} else {
|
||||
return nil, nil
|
||||
@ -331,6 +441,11 @@ func GetApplicationByClientId(clientId string) (*Application, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = extendApplicationWithSigninItems(&application)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &application, nil
|
||||
} else {
|
||||
return nil, nil
|
||||
@ -358,36 +473,71 @@ func GetMaskedApplication(application *Application, userId string) *Application
|
||||
application.FailedSigninFrozenTime = DefaultFailedSigninFrozenTime
|
||||
}
|
||||
|
||||
isOrgUser := false
|
||||
if userId != "" {
|
||||
if isUserIdGlobalAdmin(userId) {
|
||||
return application
|
||||
}
|
||||
|
||||
user, _ := GetUser(userId)
|
||||
if user != nil && user.IsApplicationAdmin(application) {
|
||||
return application
|
||||
user, err := GetUser(userId)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if user != nil {
|
||||
if user.IsApplicationAdmin(application) {
|
||||
return application
|
||||
}
|
||||
|
||||
if user.Owner == application.Organization {
|
||||
isOrgUser = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if application.ClientSecret != "" {
|
||||
application.ClientSecret = "***"
|
||||
application.ClientSecret = "***"
|
||||
application.Cert = "***"
|
||||
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") {
|
||||
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.MasterPassword != "" {
|
||||
application.OrganizationObj.MasterPassword = "***"
|
||||
}
|
||||
if application.OrganizationObj.DefaultPassword != "" {
|
||||
application.OrganizationObj.DefaultPassword = "***"
|
||||
}
|
||||
if application.OrganizationObj.MasterVerificationCode != "" {
|
||||
application.OrganizationObj.MasterVerificationCode = "***"
|
||||
}
|
||||
if application.OrganizationObj.PasswordType != "" {
|
||||
application.OrganizationObj.PasswordType = "***"
|
||||
}
|
||||
if application.OrganizationObj.PasswordSalt != "" {
|
||||
application.OrganizationObj.PasswordSalt = "***"
|
||||
application.OrganizationObj.MasterPassword = "***"
|
||||
application.OrganizationObj.DefaultPassword = "***"
|
||||
application.OrganizationObj.MasterVerificationCode = "***"
|
||||
application.OrganizationObj.PasswordType = "***"
|
||||
application.OrganizationObj.PasswordSalt = "***"
|
||||
application.OrganizationObj.InitScore = -1
|
||||
application.OrganizationObj.EnableSoftDeletion = false
|
||||
|
||||
if !isOrgUser {
|
||||
application.OrganizationObj.MfaItems = nil
|
||||
if !application.OrganizationObj.IsProfilePublic {
|
||||
application.OrganizationObj.AccountItems = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -405,8 +555,12 @@ func GetMaskedApplications(applications []*Application, userId string) []*Applic
|
||||
return applications
|
||||
}
|
||||
|
||||
func GetAllowedApplications(applications []*Application, userId string) ([]*Application, error) {
|
||||
if userId == "" || isUserIdGlobalAdmin(userId) {
|
||||
func GetAllowedApplications(applications []*Application, userId string, lang string) ([]*Application, error) {
|
||||
if userId == "" {
|
||||
return nil, fmt.Errorf(i18n.Translate(lang, "auth:Unauthorized operation"))
|
||||
}
|
||||
|
||||
if isUserIdGlobalAdmin(userId) {
|
||||
return applications, nil
|
||||
}
|
||||
|
||||
@ -414,7 +568,11 @@ func GetAllowedApplications(applications []*Application, userId string) ([]*Appl
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if user != nil && user.IsAdmin {
|
||||
if user == nil {
|
||||
return nil, fmt.Errorf(i18n.Translate(lang, "auth:Unauthorized operation"))
|
||||
}
|
||||
|
||||
if user.IsAdmin {
|
||||
return applications, nil
|
||||
}
|
||||
|
||||
@ -529,7 +687,7 @@ func (application *Application) GetId() string {
|
||||
}
|
||||
|
||||
func (application *Application) IsRedirectUriValid(redirectUri string) bool {
|
||||
redirectUris := append([]string{"http://localhost:", "https://localhost:", "http://127.0.0.1:", "http://casdoor-app"}, application.RedirectUris...)
|
||||
redirectUris := append([]string{"http://localhost:", "https://localhost:", "http://127.0.0.1:", "http://casdoor-app", ".chromiumapp.org"}, application.RedirectUris...)
|
||||
for _, targetUri := range redirectUris {
|
||||
targetUriRegex := regexp.MustCompile(targetUri)
|
||||
if targetUriRegex.MatchString(redirectUri) || strings.Contains(redirectUri, targetUri) {
|
||||
@ -602,6 +760,17 @@ func (application *Application) IsLdapEnabled() bool {
|
||||
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) {
|
||||
applications, err := GetApplications("")
|
||||
if err != nil {
|
||||
|
@ -38,12 +38,38 @@ func (application *Application) GetProviderByCategory(category string) (*Provide
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (application *Application) GetEmailProvider() (*Provider, error) {
|
||||
return application.GetProviderByCategory("Email")
|
||||
func (application *Application) GetProviderByCategoryAndRule(category string, method string) (*Provider, error) {
|
||||
providers, err := GetProviders(application.Organization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m := map[string]*Provider{}
|
||||
for _, provider := range providers {
|
||||
if provider.Category != category {
|
||||
continue
|
||||
}
|
||||
|
||||
m[provider.Name] = provider
|
||||
}
|
||||
|
||||
for _, providerItem := range application.Providers {
|
||||
if providerItem.Rule == method || (providerItem.Rule == "all" || providerItem.Rule == "" || providerItem.Rule == "None") {
|
||||
if provider, ok := m[providerItem.Name]; ok {
|
||||
return provider, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (application *Application) GetSmsProvider() (*Provider, error) {
|
||||
return application.GetProviderByCategory("SMS")
|
||||
func (application *Application) GetEmailProvider(method string) (*Provider, error) {
|
||||
return application.GetProviderByCategoryAndRule("Email", method)
|
||||
}
|
||||
|
||||
func (application *Application) GetSmsProvider(method string) (*Provider, error) {
|
||||
return application.GetProviderByCategoryAndRule("SMS", method)
|
||||
}
|
||||
|
||||
func (application *Application) GetStorageProvider() (*Provider, error) {
|
||||
|
@ -205,16 +205,41 @@ func (p *Cert) GetId() string {
|
||||
}
|
||||
|
||||
func (p *Cert) populateContent() error {
|
||||
if p.Certificate == "" || p.PrivateKey == "" {
|
||||
certificate, privateKey, err := generateRsaKeys(p.BitSize, p.ExpireInYears, p.Name, p.Owner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Certificate = certificate
|
||||
p.PrivateKey = privateKey
|
||||
if p.Certificate != "" && p.PrivateKey != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
BIN
object/cert.go~
BIN
object/cert.go~
Binary file not shown.
@ -184,6 +184,15 @@ func CheckInvitationCode(application *Application, organization *Organization, a
|
||||
}
|
||||
}
|
||||
|
||||
func CheckInvitationDefaultCode(code string, defaultCode string, lang string) error {
|
||||
if matched, err := util.IsInvitationCodeMatch(code, defaultCode); err != nil {
|
||||
return err
|
||||
} else if !matched {
|
||||
return fmt.Errorf(i18n.Translate(lang, "check:Default code does not match the code's matching rules"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkSigninErrorTimes(user *User, lang string) error {
|
||||
failedSigninLimit, failedSigninFrozenTime, err := GetFailedSigninConfigByUser(user)
|
||||
if err != nil {
|
||||
|
@ -28,6 +28,10 @@ type Dashboard struct {
|
||||
}
|
||||
|
||||
func GetDashboard(owner string) (*Dashboard, error) {
|
||||
if owner == "All" {
|
||||
owner = ""
|
||||
}
|
||||
|
||||
dashboard := &Dashboard{
|
||||
OrganizationCounts: make([]int, 31),
|
||||
UserCounts: make([]int, 31),
|
||||
@ -36,14 +40,13 @@ func GetDashboard(owner string) (*Dashboard, error) {
|
||||
SubscriptionCounts: make([]int, 31),
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
organizations := []Organization{}
|
||||
users := []User{}
|
||||
providers := []Provider{}
|
||||
applications := []Application{}
|
||||
subscriptions := []Subscription{}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(5)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
@ -17,6 +17,7 @@ package object
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
@ -30,13 +31,13 @@ type Group struct {
|
||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
|
||||
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
Manager string `xorm:"varchar(100)" json:"manager"`
|
||||
ContactEmail string `xorm:"varchar(100)" json:"contactEmail"`
|
||||
Type string `xorm:"varchar(100)" json:"type"`
|
||||
ParentId string `xorm:"varchar(100)" json:"parentId"`
|
||||
IsTopGroup bool `xorm:"bool" json:"isTopGroup"`
|
||||
Users []*User `xorm:"-" json:"users"`
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
Manager string `xorm:"varchar(100)" json:"manager"`
|
||||
ContactEmail string `xorm:"varchar(100)" json:"contactEmail"`
|
||||
Type string `xorm:"varchar(100)" json:"type"`
|
||||
ParentId string `xorm:"varchar(100)" json:"parentId"`
|
||||
IsTopGroup bool `xorm:"bool" json:"isTopGroup"`
|
||||
Users []string `xorm:"-" json:"users"`
|
||||
|
||||
Title string `json:"title,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
@ -288,6 +289,55 @@ func GetGroupUsers(groupId string) ([]*User, error) {
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func ExtendGroupWithUsers(group *Group) error {
|
||||
if group == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
users, err := GetUsers(group.Owner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
groupId := group.GetId()
|
||||
userIds := []string{}
|
||||
for _, user := range users {
|
||||
if util.InSlice(user.Groups, groupId) {
|
||||
userIds = append(userIds, user.GetId())
|
||||
}
|
||||
}
|
||||
|
||||
group.Users = userIds
|
||||
return nil
|
||||
}
|
||||
|
||||
func ExtendGroupsWithUsers(groups []*Group) error {
|
||||
var wg sync.WaitGroup
|
||||
errChan := make(chan error, len(groups))
|
||||
|
||||
for _, group := range groups {
|
||||
wg.Add(1)
|
||||
go func(group *Group) {
|
||||
defer wg.Done()
|
||||
err := ExtendGroupWithUsers(group)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
}
|
||||
}(group)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(errChan)
|
||||
|
||||
for err := range errChan {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GroupChangeTrigger(oldName, newName string) error {
|
||||
session := ormer.Engine.NewSession()
|
||||
defer session.Close()
|
||||
|
@ -184,6 +184,7 @@ func initBuiltInApplication() {
|
||||
{Name: "Password", DisplayName: "Password", Rule: "All"},
|
||||
{Name: "Verification code", DisplayName: "Verification code", Rule: "All"},
|
||||
{Name: "WebAuthn", DisplayName: "WebAuthn", Rule: "None"},
|
||||
{Name: "Face ID", DisplayName: "Face ID", Rule: "None"},
|
||||
},
|
||||
SignupItems: []*SignupItem{
|
||||
{Name: "ID", Visible: false, Required: true, Prompted: false, Rule: "Random"},
|
||||
@ -197,6 +198,7 @@ func initBuiltInApplication() {
|
||||
},
|
||||
Tags: []string{},
|
||||
RedirectUris: []string{},
|
||||
TokenFormat: "JWT",
|
||||
TokenFields: []string{},
|
||||
ExpireInHours: 168,
|
||||
FormOffset: 2,
|
||||
|
@ -17,24 +17,35 @@ package object
|
||||
import (
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/casvisor/casvisor-go-sdk/casvisorsdk"
|
||||
)
|
||||
|
||||
type InitData struct {
|
||||
Organizations []*Organization `json:"organizations"`
|
||||
Applications []*Application `json:"applications"`
|
||||
Users []*User `json:"users"`
|
||||
Certs []*Cert `json:"certs"`
|
||||
Providers []*Provider `json:"providers"`
|
||||
Ldaps []*Ldap `json:"ldaps"`
|
||||
Models []*Model `json:"models"`
|
||||
Permissions []*Permission `json:"permissions"`
|
||||
Payments []*Payment `json:"payments"`
|
||||
Products []*Product `json:"products"`
|
||||
Resources []*Resource `json:"resources"`
|
||||
Roles []*Role `json:"roles"`
|
||||
Syncers []*Syncer `json:"syncers"`
|
||||
Tokens []*Token `json:"tokens"`
|
||||
Webhooks []*Webhook `json:"webhooks"`
|
||||
Organizations []*Organization `json:"organizations"`
|
||||
Applications []*Application `json:"applications"`
|
||||
Users []*User `json:"users"`
|
||||
Certs []*Cert `json:"certs"`
|
||||
Providers []*Provider `json:"providers"`
|
||||
Ldaps []*Ldap `json:"ldaps"`
|
||||
Models []*Model `json:"models"`
|
||||
Permissions []*Permission `json:"permissions"`
|
||||
Payments []*Payment `json:"payments"`
|
||||
Products []*Product `json:"products"`
|
||||
Resources []*Resource `json:"resources"`
|
||||
Roles []*Role `json:"roles"`
|
||||
Syncers []*Syncer `json:"syncers"`
|
||||
Tokens []*Token `json:"tokens"`
|
||||
Webhooks []*Webhook `json:"webhooks"`
|
||||
Groups []*Group `json:"groups"`
|
||||
Adapters []*Adapter `json:"adapters"`
|
||||
Enforcers []*Enforcer `json:"enforcers"`
|
||||
Plans []*Plan `json:"plans"`
|
||||
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"`
|
||||
}
|
||||
|
||||
func InitFromFile() {
|
||||
@ -94,6 +105,36 @@ func InitFromFile() {
|
||||
for _, webhook := range initData.Webhooks {
|
||||
initDefinedWebhook(webhook)
|
||||
}
|
||||
for _, group := range initData.Groups {
|
||||
initDefinedGroup(group)
|
||||
}
|
||||
for _, adapter := range initData.Adapters {
|
||||
initDefinedAdapter(adapter)
|
||||
}
|
||||
for _, enforcer := range initData.Enforcers {
|
||||
initDefinedEnforcer(enforcer)
|
||||
}
|
||||
for _, plan := range initData.Plans {
|
||||
initDefinedPlan(plan)
|
||||
}
|
||||
for _, pricing := range initData.Pricings {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,6 +161,16 @@ func readInitDataFromFile(filePath string) (*InitData, error) {
|
||||
Syncers: []*Syncer{},
|
||||
Tokens: []*Token{},
|
||||
Webhooks: []*Webhook{},
|
||||
Groups: []*Group{},
|
||||
Adapters: []*Adapter{},
|
||||
Enforcers: []*Enforcer{},
|
||||
Plans: []*Plan{},
|
||||
Pricings: []*Pricing{},
|
||||
Invitations: []*Invitation{},
|
||||
Records: []*casvisorsdk.Record{},
|
||||
Sessions: []*Session{},
|
||||
Subscriptions: []*Subscription{},
|
||||
Transactions: []*Transaction{},
|
||||
}
|
||||
err := util.JsonToStruct(s, data)
|
||||
if err != nil {
|
||||
@ -190,7 +241,21 @@ func readInitDataFromFile(filePath string) (*InitData, error) {
|
||||
webhook.Headers = []*Header{}
|
||||
}
|
||||
}
|
||||
|
||||
for _, plan := range data.Plans {
|
||||
if plan.PaymentProviders == nil {
|
||||
plan.PaymentProviders = []string{}
|
||||
}
|
||||
}
|
||||
for _, pricing := range data.Pricings {
|
||||
if pricing.Plans == nil {
|
||||
pricing.Plans = []string{}
|
||||
}
|
||||
}
|
||||
for _, session := range data.Sessions {
|
||||
if session.SessionId == nil {
|
||||
session.SessionId = []string{}
|
||||
}
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
@ -434,3 +499,136 @@ func initDefinedWebhook(webhook *Webhook) {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func initDefinedGroup(group *Group) {
|
||||
existed, err := getGroup(group.Owner, group.Name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
return
|
||||
}
|
||||
group.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddGroup(group)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func initDefinedAdapter(adapter *Adapter) {
|
||||
existed, err := getAdapter(adapter.Owner, adapter.Name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
return
|
||||
}
|
||||
adapter.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddAdapter(adapter)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func initDefinedEnforcer(enforcer *Enforcer) {
|
||||
existed, err := getEnforcer(enforcer.Owner, enforcer.Name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
return
|
||||
}
|
||||
enforcer.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddEnforcer(enforcer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func initDefinedPlan(plan *Plan) {
|
||||
existed, err := getPlan(plan.Owner, plan.Name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
return
|
||||
}
|
||||
plan.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddPlan(plan)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func initDefinedPricing(pricing *Pricing) {
|
||||
existed, err := getPlan(pricing.Owner, pricing.Name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
return
|
||||
}
|
||||
pricing.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddPricing(pricing)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func initDefinedInvitation(invitation *Invitation) {
|
||||
existed, err := getInvitation(invitation.Owner, invitation.Name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
return
|
||||
}
|
||||
invitation.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddInvitation(invitation, "en")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func initDefinedRecord(record *casvisorsdk.Record) {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
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 {
|
||||
return
|
||||
}
|
||||
transaction.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddTransaction(transaction)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
@ -96,6 +96,56 @@ func writeInitDataToFile(filePath string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
groups, err := GetGroups("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
adapters, err := GetAdapters("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
enforcers, err := GetEnforcers("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
plans, err := GetPlans("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pricings, err := GetPricings("")
|
||||
if err != nil {
|
||||
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{
|
||||
Organizations: organizations,
|
||||
Applications: applications,
|
||||
@ -112,6 +162,16 @@ func writeInitDataToFile(filePath string) error {
|
||||
Syncers: syncers,
|
||||
Tokens: tokens,
|
||||
Webhooks: webhooks,
|
||||
Groups: groups,
|
||||
Adapters: adapters,
|
||||
Enforcers: enforcers,
|
||||
Plans: plans,
|
||||
Pricings: pricings,
|
||||
Invitations: invitations,
|
||||
Records: records,
|
||||
Sessions: sessions,
|
||||
Subscriptions: subscriptions,
|
||||
Transactions: transactions,
|
||||
}
|
||||
|
||||
text := util.StructToJsonFormatted(data)
|
||||
|
@ -40,6 +40,7 @@ type Invitation struct {
|
||||
Phone string `xorm:"varchar(100)" json:"phone"`
|
||||
|
||||
SignupGroup string `xorm:"varchar(100)" json:"signupGroup"`
|
||||
DefaultCode string `xorm:"varchar(100)" json:"defaultCode"`
|
||||
|
||||
State string `xorm:"varchar(100)" json:"state"`
|
||||
}
|
||||
@ -93,7 +94,45 @@ func GetInvitation(id string) (*Invitation, error) {
|
||||
return getInvitation(owner, name)
|
||||
}
|
||||
|
||||
func UpdateInvitation(id string, invitation *Invitation) (bool, error) {
|
||||
func GetInvitationByCode(code string, organizationName string, lang string) (*Invitation, string) {
|
||||
invitations, err := GetInvitations(organizationName)
|
||||
if err != nil {
|
||||
return nil, err.Error()
|
||||
}
|
||||
errMsg := ""
|
||||
for _, invitation := range invitations {
|
||||
if isValid, msg := invitation.SimpleCheckInvitationCode(code, lang); isValid {
|
||||
return invitation, msg
|
||||
} else if msg != "" && errMsg == "" {
|
||||
errMsg = msg
|
||||
}
|
||||
}
|
||||
|
||||
if errMsg != "" {
|
||||
return nil, errMsg
|
||||
} else {
|
||||
return nil, i18n.Translate(lang, "check:Invitation code is invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func GetMaskedInvitation(invitation *Invitation) *Invitation {
|
||||
if invitation == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
invitation.CreatedTime = ""
|
||||
invitation.UpdatedTime = ""
|
||||
invitation.Code = "***"
|
||||
invitation.DefaultCode = "***"
|
||||
invitation.IsRegexp = false
|
||||
invitation.Quota = -1
|
||||
invitation.UsedCount = -1
|
||||
invitation.SignupGroup = ""
|
||||
|
||||
return invitation
|
||||
}
|
||||
|
||||
func UpdateInvitation(id string, invitation *Invitation, lang string) (bool, error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
if p, err := getInvitation(owner, name); err != nil {
|
||||
return false, err
|
||||
@ -107,6 +146,11 @@ func UpdateInvitation(id string, invitation *Invitation) (bool, error) {
|
||||
invitation.IsRegexp = isRegexp
|
||||
}
|
||||
|
||||
err := CheckInvitationDefaultCode(invitation.Code, invitation.DefaultCode, lang)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(invitation)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@ -115,13 +159,18 @@ func UpdateInvitation(id string, invitation *Invitation) (bool, error) {
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
func AddInvitation(invitation *Invitation) (bool, error) {
|
||||
func AddInvitation(invitation *Invitation, lang string) (bool, error) {
|
||||
if isRegexp, err := util.IsRegexp(invitation.Code); err != nil {
|
||||
return false, err
|
||||
} else {
|
||||
invitation.IsRegexp = isRegexp
|
||||
}
|
||||
|
||||
err := CheckInvitationDefaultCode(invitation.Code, invitation.DefaultCode, lang)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
affected, err := ormer.Engine.Insert(invitation)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@ -147,7 +196,7 @@ func VerifyInvitation(id string) (payment *Payment, attachInfo map[string]interf
|
||||
return nil, nil, fmt.Errorf("the invitation: %s does not exist", id)
|
||||
}
|
||||
|
||||
func (invitation *Invitation) IsInvitationCodeValid(application *Application, invitationCode string, username string, email string, phone string, lang string) (bool, string) {
|
||||
func (invitation *Invitation) SimpleCheckInvitationCode(invitationCode string, lang string) (bool, string) {
|
||||
if matched, err := util.IsInvitationCodeMatch(invitation.Code, invitationCode); err != nil {
|
||||
return false, err.Error()
|
||||
} else if !matched {
|
||||
@ -160,15 +209,6 @@ func (invitation *Invitation) IsInvitationCodeValid(application *Application, in
|
||||
if invitation.UsedCount >= invitation.Quota {
|
||||
return false, i18n.Translate(lang, "check:Invitation code exhausted")
|
||||
}
|
||||
if application.IsSignupItemRequired("Username") && invitation.Username != "" && invitation.Username != username {
|
||||
return false, i18n.Translate(lang, "check:Please register using the username corresponding to the invitation code")
|
||||
}
|
||||
if application.IsSignupItemRequired("Email") && invitation.Email != "" && invitation.Email != email {
|
||||
return false, i18n.Translate(lang, "check:Please register using the email corresponding to the invitation code")
|
||||
}
|
||||
if application.IsSignupItemRequired("Phone") && invitation.Phone != "" && invitation.Phone != phone {
|
||||
return false, i18n.Translate(lang, "check:Please register using the phone corresponding to the invitation code")
|
||||
}
|
||||
|
||||
// Determine whether the invitation code is in the form of a regular expression other than pure numbers and letters
|
||||
if invitation.IsRegexp {
|
||||
@ -179,3 +219,19 @@ func (invitation *Invitation) IsInvitationCodeValid(application *Application, in
|
||||
}
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (invitation *Invitation) IsInvitationCodeValid(application *Application, invitationCode string, username string, email string, phone string, lang string) (bool, string) {
|
||||
if isValid, msg := invitation.SimpleCheckInvitationCode(invitationCode, lang); !isValid {
|
||||
return false, msg
|
||||
}
|
||||
if application.IsSignupItemRequired("Username") && invitation.Username != "" && invitation.Username != username {
|
||||
return false, i18n.Translate(lang, "check:Please register using the username corresponding to the invitation code")
|
||||
}
|
||||
if application.IsSignupItemRequired("Email") && invitation.Email != "" && invitation.Email != email {
|
||||
return false, i18n.Translate(lang, "check:Please register using the email corresponding to the invitation code")
|
||||
}
|
||||
if application.IsSignupItemRequired("Phone") && invitation.Phone != "" && invitation.Phone != phone {
|
||||
return false, i18n.Translate(lang, "check:Please register using the phone corresponding to the invitation code")
|
||||
}
|
||||
return true, ""
|
||||
}
|
||||
|
@ -18,12 +18,8 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/casdoor/casdoor/util"
|
||||
|
||||
"github.com/beego/beego/context"
|
||||
)
|
||||
|
||||
const MfaRecoveryCodesSession = "mfa_recovery_codes"
|
||||
|
||||
type MfaProps struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
IsPreferred bool `json:"isPreferred"`
|
||||
@ -35,9 +31,9 @@ type MfaProps struct {
|
||||
}
|
||||
|
||||
type MfaInterface interface {
|
||||
Initiate(ctx *context.Context, userId string) (*MfaProps, error)
|
||||
SetupVerify(ctx *context.Context, passcode string) error
|
||||
Enable(ctx *context.Context, user *User) error
|
||||
Initiate(userId string) (*MfaProps, error)
|
||||
SetupVerify(passcode string) error
|
||||
Enable(user *User) error
|
||||
Verify(passcode string) error
|
||||
}
|
||||
|
||||
|
@ -16,90 +16,51 @@ package object
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/beego/beego/context"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
MfaCountryCodeSession = "mfa_country_code"
|
||||
MfaDestSession = "mfa_dest"
|
||||
)
|
||||
|
||||
type SmsMfa struct {
|
||||
Config *MfaProps
|
||||
*MfaProps
|
||||
}
|
||||
|
||||
func (mfa *SmsMfa) Initiate(ctx *context.Context, userId string) (*MfaProps, error) {
|
||||
recoveryCode := uuid.NewString()
|
||||
|
||||
err := ctx.Input.CruSession.Set(MfaRecoveryCodesSession, []string{recoveryCode})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (mfa *SmsMfa) Initiate(userId string) (*MfaProps, error) {
|
||||
mfaProps := MfaProps{
|
||||
MfaType: mfa.Config.MfaType,
|
||||
RecoveryCodes: []string{recoveryCode},
|
||||
MfaType: mfa.MfaType,
|
||||
}
|
||||
return &mfaProps, nil
|
||||
}
|
||||
|
||||
func (mfa *SmsMfa) SetupVerify(ctx *context.Context, passCode string) error {
|
||||
destSession := ctx.Input.CruSession.Get(MfaDestSession)
|
||||
if destSession == nil {
|
||||
return errors.New("dest session is missing")
|
||||
}
|
||||
dest := destSession.(string)
|
||||
|
||||
if !util.IsEmailValid(dest) {
|
||||
countryCodeSession := ctx.Input.CruSession.Get(MfaCountryCodeSession)
|
||||
if countryCodeSession == nil {
|
||||
return errors.New("country code is missing")
|
||||
}
|
||||
countryCode := countryCodeSession.(string)
|
||||
|
||||
dest, _ = util.GetE164Number(dest, countryCode)
|
||||
func (mfa *SmsMfa) SetupVerify(passCode string) error {
|
||||
if !util.IsEmailValid(mfa.Secret) {
|
||||
mfa.Secret, _ = util.GetE164Number(mfa.Secret, mfa.CountryCode)
|
||||
}
|
||||
|
||||
if result := CheckVerificationCode(dest, passCode, "en"); result.Code != VerificationSuccess {
|
||||
result, err := CheckVerificationCode(mfa.Secret, passCode, "en")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result.Code != VerificationSuccess {
|
||||
return errors.New(result.Msg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mfa *SmsMfa) Enable(ctx *context.Context, user *User) error {
|
||||
recoveryCodes := ctx.Input.CruSession.Get(MfaRecoveryCodesSession).([]string)
|
||||
if len(recoveryCodes) == 0 {
|
||||
return fmt.Errorf("recovery codes is missing")
|
||||
}
|
||||
|
||||
func (mfa *SmsMfa) Enable(user *User) error {
|
||||
columns := []string{"recovery_codes", "preferred_mfa_type"}
|
||||
|
||||
user.RecoveryCodes = append(user.RecoveryCodes, recoveryCodes...)
|
||||
user.RecoveryCodes = append(user.RecoveryCodes, mfa.RecoveryCodes...)
|
||||
if user.PreferredMfaType == "" {
|
||||
user.PreferredMfaType = mfa.Config.MfaType
|
||||
user.PreferredMfaType = mfa.MfaType
|
||||
}
|
||||
|
||||
if mfa.Config.MfaType == SmsType {
|
||||
if mfa.MfaType == SmsType {
|
||||
user.MfaPhoneEnabled = true
|
||||
columns = append(columns, "mfa_phone_enabled")
|
||||
|
||||
if user.Phone == "" {
|
||||
user.Phone = ctx.Input.CruSession.Get(MfaDestSession).(string)
|
||||
user.CountryCode = ctx.Input.CruSession.Get(MfaCountryCodeSession).(string)
|
||||
columns = append(columns, "phone", "country_code")
|
||||
}
|
||||
} else if mfa.Config.MfaType == EmailType {
|
||||
columns = append(columns, "mfa_phone_enabled", "phone", "country_code")
|
||||
} else if mfa.MfaType == EmailType {
|
||||
user.MfaEmailEnabled = true
|
||||
columns = append(columns, "mfa_email_enabled")
|
||||
|
||||
if user.Email == "" {
|
||||
user.Email = ctx.Input.CruSession.Get(MfaDestSession).(string)
|
||||
columns = append(columns, "email")
|
||||
}
|
||||
columns = append(columns, "mfa_email_enabled", "email")
|
||||
}
|
||||
|
||||
_, err := UpdateUser(user.GetId(), user, columns, false)
|
||||
@ -107,20 +68,22 @@ func (mfa *SmsMfa) Enable(ctx *context.Context, user *User) error {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx.Input.CruSession.Delete(MfaRecoveryCodesSession)
|
||||
ctx.Input.CruSession.Delete(MfaDestSession)
|
||||
ctx.Input.CruSession.Delete(MfaCountryCodeSession)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mfa *SmsMfa) Verify(passCode string) error {
|
||||
if !util.IsEmailValid(mfa.Config.Secret) {
|
||||
mfa.Config.Secret, _ = util.GetE164Number(mfa.Config.Secret, mfa.Config.CountryCode)
|
||||
if !util.IsEmailValid(mfa.Secret) {
|
||||
mfa.Secret, _ = util.GetE164Number(mfa.Secret, mfa.CountryCode)
|
||||
}
|
||||
if result := CheckVerificationCode(mfa.Config.Secret, passCode, "en"); result.Code != VerificationSuccess {
|
||||
|
||||
result, err := CheckVerificationCode(mfa.Secret, passCode, "en")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result.Code != VerificationSuccess {
|
||||
return errors.New(result.Msg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -131,7 +94,7 @@ func NewSmsMfaUtil(config *MfaProps) *SmsMfa {
|
||||
}
|
||||
}
|
||||
return &SmsMfa{
|
||||
Config: config,
|
||||
config,
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,6 +105,6 @@ func NewEmailMfaUtil(config *MfaProps) *SmsMfa {
|
||||
}
|
||||
}
|
||||
return &SmsMfa{
|
||||
Config: config,
|
||||
config,
|
||||
}
|
||||
}
|
||||
|
@ -16,28 +16,24 @@ package object
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/beego/beego/context"
|
||||
"github.com/google/uuid"
|
||||
"github.com/pquerna/otp"
|
||||
"github.com/pquerna/otp/totp"
|
||||
)
|
||||
|
||||
const (
|
||||
MfaTotpSecretSession = "mfa_totp_secret"
|
||||
MfaTotpPeriodInSeconds = 30
|
||||
)
|
||||
|
||||
type TotpMfa struct {
|
||||
Config *MfaProps
|
||||
*MfaProps
|
||||
period uint
|
||||
secretSize uint
|
||||
digits otp.Digits
|
||||
}
|
||||
|
||||
func (mfa *TotpMfa) Initiate(ctx *context.Context, userId string) (*MfaProps, error) {
|
||||
func (mfa *TotpMfa) Initiate(userId string) (*MfaProps, error) {
|
||||
//issuer := beego.AppConfig.String("appname")
|
||||
//if issuer == "" {
|
||||
// issuer = "casdoor"
|
||||
@ -55,33 +51,16 @@ func (mfa *TotpMfa) Initiate(ctx *context.Context, userId string) (*MfaProps, er
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = ctx.Input.CruSession.Set(MfaTotpSecretSession, key.Secret())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
recoveryCode := uuid.NewString()
|
||||
err = ctx.Input.CruSession.Set(MfaRecoveryCodesSession, []string{recoveryCode})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mfaProps := MfaProps{
|
||||
MfaType: mfa.Config.MfaType,
|
||||
RecoveryCodes: []string{recoveryCode},
|
||||
Secret: key.Secret(),
|
||||
URL: key.URL(),
|
||||
MfaType: mfa.MfaType,
|
||||
Secret: key.Secret(),
|
||||
URL: key.URL(),
|
||||
}
|
||||
return &mfaProps, nil
|
||||
}
|
||||
|
||||
func (mfa *TotpMfa) SetupVerify(ctx *context.Context, passcode string) error {
|
||||
secret := ctx.Input.CruSession.Get(MfaTotpSecretSession)
|
||||
if secret == nil {
|
||||
return errors.New("totp secret is missing")
|
||||
}
|
||||
|
||||
result, err := totp.ValidateCustom(passcode, secret.(string), time.Now().UTC(), totp.ValidateOpts{
|
||||
func (mfa *TotpMfa) SetupVerify(passcode string) error {
|
||||
result, err := totp.ValidateCustom(passcode, mfa.Secret, time.Now().UTC(), totp.ValidateOpts{
|
||||
Period: MfaTotpPeriodInSeconds,
|
||||
Skew: 1,
|
||||
Digits: otp.DigitsSix,
|
||||
@ -98,22 +77,13 @@ func (mfa *TotpMfa) SetupVerify(ctx *context.Context, passcode string) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (mfa *TotpMfa) Enable(ctx *context.Context, user *User) error {
|
||||
recoveryCodes := ctx.Input.CruSession.Get(MfaRecoveryCodesSession).([]string)
|
||||
if len(recoveryCodes) == 0 {
|
||||
return fmt.Errorf("recovery codes is missing")
|
||||
}
|
||||
secret := ctx.Input.CruSession.Get(MfaTotpSecretSession).(string)
|
||||
if secret == "" {
|
||||
return fmt.Errorf("totp secret is missing")
|
||||
}
|
||||
|
||||
func (mfa *TotpMfa) Enable(user *User) error {
|
||||
columns := []string{"recovery_codes", "preferred_mfa_type", "totp_secret"}
|
||||
|
||||
user.RecoveryCodes = append(user.RecoveryCodes, recoveryCodes...)
|
||||
user.TotpSecret = secret
|
||||
user.RecoveryCodes = append(user.RecoveryCodes, mfa.RecoveryCodes...)
|
||||
user.TotpSecret = mfa.Secret
|
||||
if user.PreferredMfaType == "" {
|
||||
user.PreferredMfaType = mfa.Config.MfaType
|
||||
user.PreferredMfaType = mfa.MfaType
|
||||
}
|
||||
|
||||
_, err := updateUser(user.GetId(), user, columns)
|
||||
@ -121,14 +91,11 @@ func (mfa *TotpMfa) Enable(ctx *context.Context, user *User) error {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx.Input.CruSession.Delete(MfaRecoveryCodesSession)
|
||||
ctx.Input.CruSession.Delete(MfaTotpSecretSession)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mfa *TotpMfa) Verify(passcode string) error {
|
||||
result, err := totp.ValidateCustom(passcode, mfa.Config.Secret, time.Now().UTC(), totp.ValidateOpts{
|
||||
result, err := totp.ValidateCustom(passcode, mfa.Secret, time.Now().UTC(), totp.ValidateOpts{
|
||||
Period: MfaTotpPeriodInSeconds,
|
||||
Skew: 1,
|
||||
Digits: otp.DigitsSix,
|
||||
@ -153,7 +120,7 @@ func NewTotpMfaUtil(config *MfaProps) *TotpMfa {
|
||||
}
|
||||
|
||||
return &TotpMfa{
|
||||
Config: config,
|
||||
MfaProps: config,
|
||||
period: MfaTotpPeriodInSeconds,
|
||||
secretSize: 20,
|
||||
digits: otp.DigitsSix,
|
||||
|
@ -31,6 +31,7 @@ type AccountItem struct {
|
||||
Visible bool `json:"visible"`
|
||||
ViewRule string `json:"viewRule"`
|
||||
ModifyRule string `json:"modifyRule"`
|
||||
Regex string `json:"regex"`
|
||||
}
|
||||
|
||||
type ThemeData struct {
|
||||
@ -53,6 +54,8 @@ type Organization struct {
|
||||
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
WebsiteUrl string `xorm:"varchar(100)" json:"websiteUrl"`
|
||||
Logo string `xorm:"varchar(200)" json:"logo"`
|
||||
LogoDark string `xorm:"varchar(200)" json:"logoDark"`
|
||||
Favicon string `xorm:"varchar(100)" json:"favicon"`
|
||||
PasswordType string `xorm:"varchar(100)" json:"passwordType"`
|
||||
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
|
||||
@ -342,6 +345,11 @@ func GetDefaultApplication(id string) (*Application, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = extendApplicationWithSigninItems(defaultApplication)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return defaultApplication, nil
|
||||
}
|
||||
|
||||
@ -453,6 +461,16 @@ func organizationChangeTrigger(oldName string, newName string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
record := new(Record)
|
||||
record.Owner = newName
|
||||
record.Organization = newName
|
||||
_, err = session.Where("organization=?", oldName).Update(record)
|
||||
if err != nil {
|
||||
if err.Error() != "no columns found to be updated" {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
resource := new(Resource)
|
||||
resource.Owner = newName
|
||||
_, err = session.Where("owner=?", oldName).Update(resource)
|
||||
|
@ -23,6 +23,8 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/casvisor/casvisor-go-sdk/casvisorsdk"
|
||||
|
||||
"github.com/beego/beego"
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
@ -30,8 +32,9 @@ import (
|
||||
_ "github.com/denisenkom/go-mssqldb" // db = mssql
|
||||
_ "github.com/go-sql-driver/mysql" // db = mysql
|
||||
_ "github.com/lib/pq" // db = postgres
|
||||
"github.com/xorm-io/core"
|
||||
"github.com/xorm-io/xorm"
|
||||
"github.com/xorm-io/xorm/core"
|
||||
"github.com/xorm-io/xorm/names"
|
||||
_ "modernc.org/sqlite" // db = sqlite
|
||||
)
|
||||
|
||||
@ -96,7 +99,7 @@ func InitAdapter() {
|
||||
}
|
||||
|
||||
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
||||
tbMapper := core.NewPrefixMapper(core.SnakeMapper{}, tableNamePrefix)
|
||||
tbMapper := names.NewPrefixMapper(names.SnakeMapper{}, tableNamePrefix)
|
||||
ormer.Engine.SetTableMapper(tbMapper)
|
||||
}
|
||||
|
||||
@ -116,6 +119,7 @@ type Ormer struct {
|
||||
driverName string
|
||||
dataSourceName string
|
||||
dbName string
|
||||
Db *sql.DB
|
||||
Engine *xorm.Engine
|
||||
}
|
||||
|
||||
@ -125,6 +129,13 @@ func finalizer(a *Ormer) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if a.Db != nil {
|
||||
err = a.Db.Close()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewAdapter is the constructor for Ormer.
|
||||
@ -146,6 +157,26 @@ func NewAdapter(driverName string, dataSourceName string, dbName string) (*Ormer
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// NewAdapterFromdb is the constructor for Ormer.
|
||||
func NewAdapterFromDb(driverName string, dataSourceName string, dbName string, db *sql.DB) (*Ormer, error) {
|
||||
a := &Ormer{}
|
||||
a.driverName = driverName
|
||||
a.dataSourceName = dataSourceName
|
||||
a.dbName = dbName
|
||||
a.Db = db
|
||||
|
||||
// Open the DB, create it if not existed.
|
||||
err := a.openFromDb(a.Db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Call the destructor when the object is released.
|
||||
runtime.SetFinalizer(a, finalizer)
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func refineDataSourceNameForPostgres(dataSourceName string) string {
|
||||
reg := regexp.MustCompile(`dbname=[^ ]+\s*`)
|
||||
return reg.ReplaceAllString(dataSourceName, "")
|
||||
@ -224,6 +255,30 @@ func (a *Ormer) open() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Ormer) openFromDb(db *sql.DB) error {
|
||||
dataSourceName := a.dataSourceName + a.dbName
|
||||
if a.driverName != "mysql" {
|
||||
dataSourceName = a.dataSourceName
|
||||
}
|
||||
|
||||
xormDb := core.FromDB(db)
|
||||
|
||||
engine, err := xorm.NewEngineWithDB(a.driverName, dataSourceName, xormDb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if a.driverName == "postgres" {
|
||||
schema := util.GetValueFromDataSourceName("search_path", dataSourceName)
|
||||
if schema != "" {
|
||||
engine.SetSchema(schema)
|
||||
}
|
||||
}
|
||||
|
||||
a.Engine = engine
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Ormer) close() {
|
||||
_ = a.Engine.Close()
|
||||
a.Engine = nil
|
||||
@ -333,11 +388,21 @@ func (a *Ormer) createTable() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Transaction))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Syncer))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(casvisorsdk.Record))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Webhook))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -312,8 +312,6 @@ func GetPaymentProvider(p *Provider) (pp.PaymentProvider, error) {
|
||||
} else {
|
||||
return nil, fmt.Errorf("the payment provider type: %s is not supported", p.Type)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (p *Provider) GetId() string {
|
||||
|
109
object/record.go
109
object/record.go
@ -15,6 +15,7 @@
|
||||
package object
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@ -34,7 +35,12 @@ type Record struct {
|
||||
casvisorsdk.Record
|
||||
}
|
||||
|
||||
func NewRecord(ctx *context.Context) *casvisorsdk.Record {
|
||||
type Response struct {
|
||||
Status string `json:"status"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
func NewRecord(ctx *context.Context) (*casvisorsdk.Record, error) {
|
||||
ip := strings.Replace(util.GetIPFromRequest(ctx.Request), ": ", "", -1)
|
||||
action := strings.Replace(ctx.Request.URL.Path, "/api/", "", -1)
|
||||
requestUri := util.FilterQuery(ctx.Request.RequestURI, []string{"accessToken"})
|
||||
@ -47,6 +53,23 @@ func NewRecord(ctx *context.Context) *casvisorsdk.Record {
|
||||
object = string(ctx.Input.RequestBody)
|
||||
}
|
||||
|
||||
respBytes, err := json.Marshal(ctx.Input.Data()["json"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp Response
|
||||
err = json.Unmarshal(respBytes, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
language := ctx.Request.Header.Get("Accept-Language")
|
||||
if len(language) > 2 {
|
||||
language = language[0:2]
|
||||
}
|
||||
languageCode := conf.GetLanguage(language)
|
||||
|
||||
record := casvisorsdk.Record{
|
||||
Name: util.GenerateId(),
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
@ -55,10 +78,12 @@ func NewRecord(ctx *context.Context) *casvisorsdk.Record {
|
||||
Method: ctx.Request.Method,
|
||||
RequestUri: requestUri,
|
||||
Action: action,
|
||||
Language: languageCode,
|
||||
Object: object,
|
||||
Response: fmt.Sprintf("{status:\"%s\", msg:\"%s\"}", resp.Status, resp.Msg),
|
||||
IsTriggered: false,
|
||||
}
|
||||
return &record
|
||||
return &record, nil
|
||||
}
|
||||
|
||||
func AddRecord(record *casvisorsdk.Record) bool {
|
||||
@ -82,7 +107,12 @@ func AddRecord(record *casvisorsdk.Record) bool {
|
||||
}
|
||||
|
||||
if casvisorsdk.GetClient() == nil {
|
||||
return false
|
||||
affected, err := ormer.Engine.Insert(record)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return affected != 0
|
||||
}
|
||||
|
||||
affected, err := casvisorsdk.AddRecord(record)
|
||||
@ -93,13 +123,80 @@ func AddRecord(record *casvisorsdk.Record) bool {
|
||||
return affected
|
||||
}
|
||||
|
||||
func getFilteredWebhooks(webhooks []*Webhook, action string) []*Webhook {
|
||||
func GetRecordCount(field, value string, filterRecord *casvisorsdk.Record) (int64, error) {
|
||||
session := GetSession("", -1, -1, field, value, "", "")
|
||||
return session.Count(filterRecord)
|
||||
}
|
||||
|
||||
func GetRecords() ([]*casvisorsdk.Record, error) {
|
||||
records := []*casvisorsdk.Record{}
|
||||
err := ormer.Engine.Desc("id").Find(&records)
|
||||
if err != nil {
|
||||
return records, err
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func GetPaginationRecords(offset, limit int, field, value, sortField, sortOrder string, filterRecord *casvisorsdk.Record) ([]*casvisorsdk.Record, error) {
|
||||
records := []*casvisorsdk.Record{}
|
||||
|
||||
if sortField == "" || sortOrder == "" {
|
||||
sortField = "id"
|
||||
sortOrder = "descend"
|
||||
}
|
||||
|
||||
session := GetSession("", offset, limit, field, value, sortField, sortOrder)
|
||||
err := session.Find(&records, filterRecord)
|
||||
if err != nil {
|
||||
return records, err
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func GetRecordsByField(record *casvisorsdk.Record) ([]*casvisorsdk.Record, error) {
|
||||
records := []*casvisorsdk.Record{}
|
||||
err := ormer.Engine.Find(&records, record)
|
||||
if err != nil {
|
||||
return records, err
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func CopyRecord(record *casvisorsdk.Record) *casvisorsdk.Record {
|
||||
res := &casvisorsdk.Record{
|
||||
Owner: record.Owner,
|
||||
Name: record.Name,
|
||||
CreatedTime: record.CreatedTime,
|
||||
Organization: record.Organization,
|
||||
ClientIp: record.ClientIp,
|
||||
User: record.User,
|
||||
Method: record.Method,
|
||||
RequestUri: record.RequestUri,
|
||||
Action: record.Action,
|
||||
Language: record.Language,
|
||||
Object: record.Object,
|
||||
Response: record.Response,
|
||||
IsTriggered: record.IsTriggered,
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func getFilteredWebhooks(webhooks []*Webhook, organization string, action string) []*Webhook {
|
||||
res := []*Webhook{}
|
||||
for _, webhook := range webhooks {
|
||||
if !webhook.IsEnabled {
|
||||
continue
|
||||
}
|
||||
|
||||
if webhook.SingleOrgOnly {
|
||||
if webhook.Organization != organization {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
matched := false
|
||||
for _, event := range webhook.Events {
|
||||
if action == event {
|
||||
@ -116,13 +213,13 @@ func getFilteredWebhooks(webhooks []*Webhook, action string) []*Webhook {
|
||||
}
|
||||
|
||||
func SendWebhooks(record *casvisorsdk.Record) error {
|
||||
webhooks, err := getWebhooksByOrganization(record.Organization)
|
||||
webhooks, err := getWebhooksByOrganization("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
errs := []error{}
|
||||
webhooks = getFilteredWebhooks(webhooks, record.Action)
|
||||
webhooks = getFilteredWebhooks(webhooks, record.Organization, record.Action)
|
||||
for _, webhook := range webhooks {
|
||||
var user *User
|
||||
if webhook.IsUserExtended {
|
||||
|
@ -27,7 +27,7 @@ func getCasvisorApplication() *Application {
|
||||
}
|
||||
|
||||
for _, application := range applications {
|
||||
if strings.Contains(strings.ToLower(application.Name), "casvisor") {
|
||||
if strings.Contains(strings.ToLower(application.Name), "casvisor-my") {
|
||||
return application
|
||||
}
|
||||
}
|
||||
|
@ -179,8 +179,8 @@ type IdpSSODescriptor struct {
|
||||
}
|
||||
|
||||
type NameIDFormat struct {
|
||||
XMLName xml.Name
|
||||
Value string `xml:",innerxml"`
|
||||
// XMLName xml.Name
|
||||
Value string `xml:",innerxml"`
|
||||
}
|
||||
|
||||
type SingleSignOnService struct {
|
||||
@ -190,7 +190,7 @@ type SingleSignOnService struct {
|
||||
}
|
||||
|
||||
type Attribute struct {
|
||||
XMLName xml.Name
|
||||
// XMLName xml.Name
|
||||
Name string `xml:"Name,attr"`
|
||||
NameFormat string `xml:"NameFormat,attr"`
|
||||
FriendlyName string `xml:"FriendlyName,attr"`
|
||||
@ -198,7 +198,7 @@ type Attribute struct {
|
||||
Values []string `xml:"AttributeValue"`
|
||||
}
|
||||
|
||||
func GetSamlMeta(application *Application, host string) (*IdpEntityDescriptor, error) {
|
||||
func GetSamlMeta(application *Application, host string, enablePostBinding bool) (*IdpEntityDescriptor, error) {
|
||||
cert, err := getCertByApplication(application)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -217,6 +217,13 @@ func GetSamlMeta(application *Application, host string) (*IdpEntityDescriptor, e
|
||||
|
||||
originFrontend, originBackend := getOriginFromHost(host)
|
||||
|
||||
idpLocation := ""
|
||||
if enablePostBinding {
|
||||
idpLocation = fmt.Sprintf("%s/api/saml/redirect/%s/%s", originBackend, application.Owner, application.Name)
|
||||
} else {
|
||||
idpLocation = fmt.Sprintf("%s/login/saml/authorize/%s/%s", originFrontend, application.Owner, application.Name)
|
||||
}
|
||||
|
||||
d := IdpEntityDescriptor{
|
||||
XMLName: xml.Name{
|
||||
Local: "md:EntityDescriptor",
|
||||
@ -248,7 +255,7 @@ func GetSamlMeta(application *Application, host string) (*IdpEntityDescriptor, e
|
||||
},
|
||||
SingleSignOnService: SingleSignOnService{
|
||||
Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
|
||||
Location: fmt.Sprintf("%s/login/saml/authorize/%s/%s", originFrontend, application.Owner, application.Name),
|
||||
Location: idpLocation,
|
||||
},
|
||||
ProtocolSupportEnumeration: "urn:oasis:names:tc:SAML:2.0:protocol",
|
||||
},
|
||||
@ -266,7 +273,7 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
||||
// base64 decode
|
||||
defated, err := base64.StdEncoding.DecodeString(samlRequest)
|
||||
if err != nil {
|
||||
return "", "", method, fmt.Errorf("err: Failed to decode SAML request , %s", err.Error())
|
||||
return "", "", "", fmt.Errorf("err: Failed to decode SAML request, %s", err.Error())
|
||||
}
|
||||
|
||||
// decompress
|
||||
@ -274,7 +281,7 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
||||
rdr := flate.NewReader(bytes.NewReader(defated))
|
||||
|
||||
for {
|
||||
_, err := io.CopyN(&buffer, rdr, 1024)
|
||||
_, err = io.CopyN(&buffer, rdr, 1024)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
@ -286,12 +293,12 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
||||
var authnRequest saml.AuthNRequest
|
||||
err = xml.Unmarshal(buffer.Bytes(), &authnRequest)
|
||||
if err != nil {
|
||||
return "", "", method, fmt.Errorf("err: Failed to unmarshal AuthnRequest, please check the SAML request. %s", err.Error())
|
||||
return "", "", "", fmt.Errorf("err: Failed to unmarshal AuthnRequest, please check the SAML request, %s", err.Error())
|
||||
}
|
||||
|
||||
// verify samlRequest
|
||||
if isValid := application.IsRedirectUriValid(authnRequest.Issuer); !isValid {
|
||||
return "", "", method, fmt.Errorf("err: Issuer URI: %s doesn't exist in the allowed Redirect URI list", authnRequest.Issuer)
|
||||
return "", "", "", fmt.Errorf("err: Issuer URI: %s doesn't exist in the allowed Redirect URI list", authnRequest.Issuer)
|
||||
}
|
||||
|
||||
// get certificate string
|
||||
@ -316,8 +323,13 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
||||
}
|
||||
|
||||
_, originBackend := getOriginFromHost(host)
|
||||
|
||||
// build signedResponse
|
||||
samlResponse, _ := NewSamlResponse(application, user, originBackend, certificate, authnRequest.AssertionConsumerServiceURL, authnRequest.Issuer, authnRequest.ID, application.RedirectUris)
|
||||
samlResponse, err := NewSamlResponse(application, user, originBackend, certificate, authnRequest.AssertionConsumerServiceURL, authnRequest.Issuer, authnRequest.ID, application.RedirectUris)
|
||||
if err != nil {
|
||||
return "", "", "", fmt.Errorf("err: NewSamlResponse() error, %s", err.Error())
|
||||
}
|
||||
|
||||
randomKeyStore := &X509Key{
|
||||
PrivateKey: cert.PrivateKey,
|
||||
X509Certificate: certificate,
|
||||
@ -329,18 +341,23 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
||||
ctx.Canonicalizer = dsig.MakeC14N10ExclusiveCanonicalizerWithPrefixList("")
|
||||
}
|
||||
|
||||
//signedXML, err := ctx.SignEnvelopedLimix(samlResponse)
|
||||
//if err != nil {
|
||||
// signedXML, err := ctx.SignEnvelopedLimix(samlResponse)
|
||||
// if err != nil {
|
||||
// return "", "", fmt.Errorf("err: %s", err.Error())
|
||||
//}
|
||||
// }
|
||||
|
||||
sig, err := ctx.ConstructSignature(samlResponse, true)
|
||||
if err != nil {
|
||||
return "", "", "", fmt.Errorf("err: Failed to serializes the SAML request into bytes, %s", err.Error())
|
||||
}
|
||||
|
||||
samlResponse.InsertChildAt(1, sig)
|
||||
|
||||
doc := etree.NewDocument()
|
||||
doc.SetRoot(samlResponse)
|
||||
xmlBytes, err := doc.WriteToBytes()
|
||||
if err != nil {
|
||||
return "", "", method, fmt.Errorf("err: Failed to serializes the SAML request into bytes, %s", err.Error())
|
||||
return "", "", "", fmt.Errorf("err: Failed to serializes the SAML request into bytes, %s", err.Error())
|
||||
}
|
||||
|
||||
// compress
|
||||
@ -348,16 +365,19 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
||||
flated := bytes.NewBuffer(nil)
|
||||
writer, err := flate.NewWriter(flated, flate.DefaultCompression)
|
||||
if err != nil {
|
||||
return "", "", method, err
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
_, err = writer.Write(xmlBytes)
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
err = writer.Close()
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
xmlBytes = flated.Bytes()
|
||||
}
|
||||
// base64 encode
|
||||
@ -366,12 +386,12 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
||||
}
|
||||
|
||||
// NewSamlResponse11 return a saml1.1 response(not 2.0)
|
||||
func NewSamlResponse11(user *User, requestID string, host string) *etree.Element {
|
||||
func NewSamlResponse11(user *User, requestID string, host string) (*etree.Element, error) {
|
||||
samlResponse := &etree.Element{
|
||||
Space: "samlp",
|
||||
Tag: "Response",
|
||||
}
|
||||
// create samlresponse
|
||||
|
||||
samlResponse.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:1.0:protocol")
|
||||
samlResponse.CreateAttr("MajorVersion", "1")
|
||||
samlResponse.CreateAttr("MinorVersion", "1")
|
||||
@ -424,11 +444,15 @@ func NewSamlResponse11(user *User, requestID string, host string) *etree.Element
|
||||
subjectConfirmationInAttribute := subjectInAttribute.CreateElement("saml:SubjectConfirmation")
|
||||
subjectConfirmationInAttribute.CreateElement("saml:ConfirmationMethod").SetText("urn:oasis:names:tc:SAML:1.0:cm:artifact")
|
||||
|
||||
data, _ := json.Marshal(user)
|
||||
tmp := map[string]string{}
|
||||
err := json.Unmarshal(data, &tmp)
|
||||
data, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tmp := map[string]string{}
|
||||
err = json.Unmarshal(data, &tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for k, v := range tmp {
|
||||
@ -440,5 +464,10 @@ func NewSamlResponse11(user *User, requestID string, host string) *etree.Element
|
||||
}
|
||||
}
|
||||
|
||||
return samlResponse
|
||||
return samlResponse, nil
|
||||
}
|
||||
|
||||
func GetSamlRedirectAddress(owner string, application string, relayState string, samlRequest string, host string) string {
|
||||
originF, _ := getOriginFromHost(host)
|
||||
return fmt.Sprintf("%s/login/saml/authorize/%s/%s?relayState=%s&samlRequest=%s", originF, owner, application, relayState, samlRequest)
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ func getSmsClient(provider *Provider) (sender.SmsClient, error) {
|
||||
if provider.Type == sender.HuaweiCloud || provider.Type == sender.AzureACS {
|
||||
client, err = sender.NewSmsClient(provider.Type, provider.ClientId, provider.ClientSecret, provider.SignName, provider.TemplateCode, provider.ProviderUrl, provider.AppId)
|
||||
} else if provider.Type == "Custom HTTP SMS" {
|
||||
client, err = newHttpSmsClient(provider.Endpoint, provider.Method, provider.Title)
|
||||
client, err = newHttpSmsClient(provider.Endpoint, provider.Method, provider.Title, provider.TemplateCode)
|
||||
} else {
|
||||
client, err = sender.NewSmsClient(provider.Type, provider.ClientId, provider.ClientSecret, provider.SignName, provider.TemplateCode, provider.AppId)
|
||||
}
|
||||
|
@ -27,20 +27,26 @@ type HttpSmsClient struct {
|
||||
endpoint string
|
||||
method string
|
||||
paramName string
|
||||
template string
|
||||
}
|
||||
|
||||
func newHttpSmsClient(endpoint string, method string, paramName string) (*HttpSmsClient, error) {
|
||||
func newHttpSmsClient(endpoint, method, paramName, template string) (*HttpSmsClient, error) {
|
||||
if template == "" {
|
||||
template = "%s"
|
||||
}
|
||||
client := &HttpSmsClient{
|
||||
endpoint: endpoint,
|
||||
method: method,
|
||||
paramName: paramName,
|
||||
template: template,
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (c *HttpSmsClient) SendMessage(param map[string]string, targetPhoneNumber ...string) error {
|
||||
phoneNumber := targetPhoneNumber[0]
|
||||
content := param["code"]
|
||||
code := param["code"]
|
||||
content := fmt.Sprintf(c.template, code)
|
||||
|
||||
var req *http.Request
|
||||
var err error
|
||||
|
@ -109,14 +109,17 @@ func GetUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool
|
||||
|
||||
func getStorageProvider(provider *Provider, lang string) (oss.StorageInterface, error) {
|
||||
endpoint := getProviderEndpoint(provider)
|
||||
storageProvider := storage.GetStorageProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.RegionId, provider.Bucket, endpoint)
|
||||
storageProvider, err := storage.GetStorageProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.RegionId, provider.Bucket, endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if storageProvider == nil {
|
||||
return nil, fmt.Errorf(i18n.Translate(lang, "storage:The provider type: %s is not supported"), provider.Type)
|
||||
}
|
||||
|
||||
if provider.Domain == "" {
|
||||
provider.Domain = storageProvider.GetEndpoint()
|
||||
_, err := UpdateProvider(provider.GetId(), provider)
|
||||
_, err = UpdateProvider(provider.GetId(), provider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -39,11 +39,17 @@ type Syncer struct {
|
||||
Type string `xorm:"varchar(100)" json:"type"`
|
||||
DatabaseType string `xorm:"varchar(100)" json:"databaseType"`
|
||||
SslMode string `xorm:"varchar(100)" json:"sslMode"`
|
||||
SshType string `xorm:"varchar(100)" json:"sshType"`
|
||||
|
||||
Host string `xorm:"varchar(100)" json:"host"`
|
||||
Port int `json:"port"`
|
||||
User string `xorm:"varchar(100)" json:"user"`
|
||||
Password string `xorm:"varchar(100)" json:"password"`
|
||||
Password string `xorm:"varchar(150)" json:"password"`
|
||||
SshHost string `xorm:"varchar(100)" json:"sshHost"`
|
||||
SshPort int `json:"sshPort"`
|
||||
SshUser string `xorm:"varchar(100)" json:"sshUser"`
|
||||
SshPassword string `xorm:"varchar(150)" json:"sshPassword"`
|
||||
Cert string `xorm:"varchar(100)" json:"cert"`
|
||||
Database string `xorm:"varchar(100)" json:"database"`
|
||||
Table string `xorm:"varchar(100)" json:"table"`
|
||||
TableColumns []*TableColumn `xorm:"mediumtext" json:"tableColumns"`
|
||||
@ -279,3 +285,25 @@ func RunSyncer(syncer *Syncer) error {
|
||||
|
||||
return syncer.syncUsers()
|
||||
}
|
||||
|
||||
func TestSyncerDb(syncer Syncer) error {
|
||||
oldSyncer, err := getSyncer(syncer.Owner, syncer.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if syncer.Password == "***" {
|
||||
syncer.Password = oldSyncer.Password
|
||||
}
|
||||
|
||||
err = syncer.initAdapter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = syncer.Ormer.Engine.Ping()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -15,12 +15,17 @@
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
type OriginalUser = User
|
||||
@ -124,6 +129,19 @@ func (syncer *Syncer) calculateHash(user *OriginalUser) string {
|
||||
return util.GetMd5Hash(s)
|
||||
}
|
||||
|
||||
type dsnConnector struct {
|
||||
dsn string
|
||||
driver driver.Driver
|
||||
}
|
||||
|
||||
func (t dsnConnector) Connect(ctx context.Context) (driver.Conn, error) {
|
||||
return t.driver.Open(t.dsn)
|
||||
}
|
||||
|
||||
func (t dsnConnector) Driver() driver.Driver {
|
||||
return t.driver
|
||||
}
|
||||
|
||||
func (syncer *Syncer) initAdapter() error {
|
||||
if syncer.Ormer != nil {
|
||||
return nil
|
||||
@ -142,12 +160,38 @@ func (syncer *Syncer) initAdapter() error {
|
||||
dataSourceName = fmt.Sprintf("%s:%s@tcp(%s:%d)/", syncer.User, syncer.Password, syncer.Host, syncer.Port)
|
||||
}
|
||||
|
||||
var db *sql.DB
|
||||
var err error
|
||||
|
||||
if syncer.SshType != "" && (syncer.DatabaseType == "mysql" || syncer.DatabaseType == "postgres" || syncer.DatabaseType == "mssql") {
|
||||
var dial *ssh.Client
|
||||
if syncer.SshType == "password" {
|
||||
dial, err = DialWithPassword(syncer.SshUser, syncer.SshPassword, syncer.SshHost, syncer.SshPort)
|
||||
} else {
|
||||
dial, err = DialWithCert(syncer.SshUser, syncer.Owner+"/"+syncer.Cert, syncer.SshHost, syncer.SshPort)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if syncer.DatabaseType == "mysql" {
|
||||
dataSourceName = fmt.Sprintf("%s:%s@%s(%s:%d)/", syncer.User, syncer.Password, syncer.Owner+syncer.Name, syncer.Host, syncer.Port)
|
||||
mysql.RegisterDialContext(syncer.Owner+syncer.Name, (&ViaSSHDialer{Client: dial, Context: nil}).MysqlDial)
|
||||
} else if syncer.DatabaseType == "postgres" || syncer.DatabaseType == "mssql" {
|
||||
db = sql.OpenDB(dsnConnector{dsn: dataSourceName, driver: &ViaSSHDialer{Client: dial, Context: nil, DatabaseType: syncer.DatabaseType}})
|
||||
}
|
||||
}
|
||||
|
||||
if !isCloudIntranet {
|
||||
dataSourceName = strings.ReplaceAll(dataSourceName, "dbi.", "db.")
|
||||
}
|
||||
|
||||
var err error
|
||||
syncer.Ormer, err = NewAdapter(syncer.DatabaseType, dataSourceName, syncer.Database)
|
||||
if db != nil {
|
||||
syncer.Ormer, err = NewAdapterFromDb(syncer.DatabaseType, dataSourceName, syncer.Database, db)
|
||||
} else {
|
||||
syncer.Ormer, err = NewAdapter(syncer.DatabaseType, dataSourceName, syncer.Database)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -93,6 +93,8 @@ func (syncer *Syncer) setUserByKeyValue(user *User, key string, value string) {
|
||||
user.CreatedTime = value
|
||||
case "UpdatedTime":
|
||||
user.UpdatedTime = value
|
||||
case "DeletedTime":
|
||||
user.DeletedTime = value
|
||||
case "Id":
|
||||
user.Id = value
|
||||
case "Type":
|
||||
@ -266,6 +268,7 @@ func (syncer *Syncer) getMapFromOriginalUser(user *OriginalUser) map[string]stri
|
||||
m["Name"] = user.Name
|
||||
m["CreatedTime"] = user.CreatedTime
|
||||
m["UpdatedTime"] = user.UpdatedTime
|
||||
m["DeletedTime"] = user.DeletedTime
|
||||
m["Id"] = user.Id
|
||||
m["Type"] = user.Type
|
||||
m["Password"] = user.Password
|
||||
|
742
object/token.go
742
object/token.go
@ -16,33 +16,13 @@ package object
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/casdoor/casdoor/i18n"
|
||||
"github.com/casdoor/casdoor/idp"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/xorm-io/core"
|
||||
)
|
||||
|
||||
const (
|
||||
hourSeconds = int(time.Hour / time.Second)
|
||||
InvalidRequest = "invalid_request"
|
||||
InvalidClient = "invalid_client"
|
||||
InvalidGrant = "invalid_grant"
|
||||
UnauthorizedClient = "unauthorized_client"
|
||||
UnsupportedGrantType = "unsupported_grant_type"
|
||||
InvalidScope = "invalid_scope"
|
||||
EndpointError = "endpoint_error"
|
||||
)
|
||||
|
||||
type Code struct {
|
||||
Message string `xorm:"varchar(100)" json:"message"`
|
||||
Code string `xorm:"varchar(100)" json:"code"`
|
||||
}
|
||||
|
||||
type Token struct {
|
||||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||
@ -65,35 +45,6 @@ type Token struct {
|
||||
CodeExpireIn int64 `json:"codeExpireIn"`
|
||||
}
|
||||
|
||||
type TokenWrapper struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
IdToken string `json:"id_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
Scope string `json:"scope"`
|
||||
}
|
||||
|
||||
type TokenError struct {
|
||||
Error string `json:"error"`
|
||||
ErrorDescription string `json:"error_description,omitempty"`
|
||||
}
|
||||
|
||||
type IntrospectionResponse struct {
|
||||
Active bool `json:"active"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
ClientId string `json:"client_id,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
TokenType string `json:"token_type,omitempty"`
|
||||
Exp int64 `json:"exp,omitempty"`
|
||||
Iat int64 `json:"iat,omitempty"`
|
||||
Nbf int64 `json:"nbf,omitempty"`
|
||||
Sub string `json:"sub,omitempty"`
|
||||
Aud []string `json:"aud,omitempty"`
|
||||
Iss string `json:"iss,omitempty"`
|
||||
Jti string `json:"jti,omitempty"`
|
||||
}
|
||||
|
||||
func GetTokenCount(owner, organization, field, value string) (int64, error) {
|
||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||
return session.Count(&Token{Organization: organization})
|
||||
@ -186,6 +137,29 @@ func GetTokenByRefreshToken(refreshToken string) (*Token, error) {
|
||||
return &token, nil
|
||||
}
|
||||
|
||||
func GetTokenByTokenValue(tokenValue, tokenTypeHint string) (*Token, error) {
|
||||
switch tokenTypeHint {
|
||||
case "access_token":
|
||||
token, err := GetTokenByAccessToken(tokenValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if token != nil {
|
||||
return token, nil
|
||||
}
|
||||
case "refresh_token":
|
||||
token, err := GetTokenByRefreshToken(tokenValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if token != nil {
|
||||
return token, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func updateUsedByCode(token *Token) bool {
|
||||
affected, err := ormer.Engine.Where("code=?", token.Code).Cols("code_is_used").Update(token)
|
||||
if err != nil {
|
||||
@ -259,673 +233,3 @@ func DeleteToken(token *Token) (bool, error) {
|
||||
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
func ExpireTokenByAccessToken(accessToken string) (bool, *Application, *Token, error) {
|
||||
token, err := GetTokenByAccessToken(accessToken)
|
||||
if err != nil {
|
||||
return false, nil, nil, err
|
||||
}
|
||||
if token == nil {
|
||||
return false, nil, nil, nil
|
||||
}
|
||||
|
||||
token.ExpiresIn = 0
|
||||
affected, err := ormer.Engine.ID(core.PK{token.Owner, token.Name}).Cols("expires_in").Update(token)
|
||||
if err != nil {
|
||||
return false, nil, nil, err
|
||||
}
|
||||
|
||||
application, err := getApplication(token.Owner, token.Application)
|
||||
if err != nil {
|
||||
return false, nil, nil, err
|
||||
}
|
||||
|
||||
return affected != 0, application, token, nil
|
||||
}
|
||||
|
||||
func GetTokenByTokenAndApplication(token string, application string) (*Token, error) {
|
||||
tokenResult := Token{}
|
||||
existed, err := ormer.Engine.Where("(refresh_token = ? or access_token = ? ) and application = ?", token, token, application).Get(&tokenResult)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !existed {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &tokenResult, nil
|
||||
}
|
||||
|
||||
func CheckOAuthLogin(clientId string, responseType string, redirectUri string, scope string, state string, lang string) (string, *Application, error) {
|
||||
if responseType != "code" && responseType != "token" && responseType != "id_token" {
|
||||
return fmt.Sprintf(i18n.Translate(lang, "token:Grant_type: %s is not supported in this application"), responseType), nil, nil
|
||||
}
|
||||
|
||||
application, err := GetApplicationByClientId(clientId)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if application == nil {
|
||||
return i18n.Translate(lang, "token:Invalid client_id"), nil, nil
|
||||
}
|
||||
|
||||
if !application.IsRedirectUriValid(redirectUri) {
|
||||
return fmt.Sprintf(i18n.Translate(lang, "token:Redirect URI: %s doesn't exist in the allowed Redirect URI list"), redirectUri), application, nil
|
||||
}
|
||||
|
||||
// Mask application for /api/get-app-login
|
||||
application.ClientSecret = ""
|
||||
return "", application, nil
|
||||
}
|
||||
|
||||
func GetOAuthCode(userId string, clientId string, responseType string, redirectUri string, scope string, state string, nonce string, challenge string, host string, lang string) (*Code, error) {
|
||||
user, err := GetUser(userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
return &Code{
|
||||
Message: fmt.Sprintf("general:The user: %s doesn't exist", userId),
|
||||
Code: "",
|
||||
}, nil
|
||||
}
|
||||
if user.IsForbidden {
|
||||
return &Code{
|
||||
Message: "error: the user is forbidden to sign in, please contact the administrator",
|
||||
Code: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
msg, application, err := CheckOAuthLogin(clientId, responseType, redirectUri, scope, state, lang)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if msg != "" {
|
||||
return &Code{
|
||||
Message: msg,
|
||||
Code: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
err = ExtendUserWithRolesAndPermissions(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, nonce, scope, host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if challenge == "null" {
|
||||
challenge = ""
|
||||
}
|
||||
|
||||
token := &Token{
|
||||
Owner: application.Owner,
|
||||
Name: tokenName,
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: application.Name,
|
||||
Organization: user.Owner,
|
||||
User: user.Name,
|
||||
Code: util.GenerateClientId(),
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: application.ExpireInHours * hourSeconds,
|
||||
Scope: scope,
|
||||
TokenType: "Bearer",
|
||||
CodeChallenge: challenge,
|
||||
CodeIsUsed: false,
|
||||
CodeExpireIn: time.Now().Add(time.Minute * 5).Unix(),
|
||||
}
|
||||
_, err = AddToken(token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Code{
|
||||
Message: "",
|
||||
Code: token.Code,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func GetOAuthToken(grantType string, clientId string, clientSecret string, code string, verifier string, scope string, username string, password string, host string, refreshToken string, tag string, avatar string, lang string) (interface{}, error) {
|
||||
application, err := GetApplicationByClientId(clientId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if application == nil {
|
||||
return &TokenError{
|
||||
Error: InvalidClient,
|
||||
ErrorDescription: "client_id is invalid",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Check if grantType is allowed in the current application
|
||||
|
||||
if !IsGrantTypeValid(grantType, application.GrantTypes) && tag == "" {
|
||||
return &TokenError{
|
||||
Error: UnsupportedGrantType,
|
||||
ErrorDescription: fmt.Sprintf("grant_type: %s is not supported in this application", grantType),
|
||||
}, nil
|
||||
}
|
||||
|
||||
var token *Token
|
||||
var tokenError *TokenError
|
||||
switch grantType {
|
||||
case "authorization_code": // Authorization Code Grant
|
||||
token, tokenError, err = GetAuthorizationCodeToken(application, clientSecret, code, verifier)
|
||||
case "password": // Resource Owner Password Credentials Grant
|
||||
token, tokenError, err = GetPasswordToken(application, username, password, scope, host)
|
||||
case "client_credentials": // Client Credentials Grant
|
||||
token, tokenError, err = GetClientCredentialsToken(application, clientSecret, scope, host)
|
||||
case "refresh_token":
|
||||
refreshToken2, err := RefreshToken(grantType, refreshToken, scope, clientId, clientSecret, host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return refreshToken2, nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if tag == "wechat_miniprogram" {
|
||||
// Wechat Mini Program
|
||||
token, tokenError, err = GetWechatMiniProgramToken(application, code, host, username, avatar, lang)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if tokenError != nil {
|
||||
return tokenError, nil
|
||||
}
|
||||
|
||||
token.CodeIsUsed = true
|
||||
|
||||
go updateUsedByCode(token)
|
||||
|
||||
tokenWrapper := &TokenWrapper{
|
||||
AccessToken: token.AccessToken,
|
||||
IdToken: token.AccessToken,
|
||||
RefreshToken: token.RefreshToken,
|
||||
TokenType: token.TokenType,
|
||||
ExpiresIn: token.ExpiresIn,
|
||||
Scope: token.Scope,
|
||||
}
|
||||
|
||||
return tokenWrapper, nil
|
||||
}
|
||||
|
||||
func RefreshToken(grantType string, refreshToken string, scope string, clientId string, clientSecret string, host string) (interface{}, error) {
|
||||
// check parameters
|
||||
if grantType != "refresh_token" {
|
||||
return &TokenError{
|
||||
Error: UnsupportedGrantType,
|
||||
ErrorDescription: "grant_type should be refresh_token",
|
||||
}, nil
|
||||
}
|
||||
application, err := GetApplicationByClientId(clientId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if application == nil {
|
||||
return &TokenError{
|
||||
Error: InvalidClient,
|
||||
ErrorDescription: "client_id is invalid",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if clientSecret != "" && application.ClientSecret != clientSecret {
|
||||
return &TokenError{
|
||||
Error: InvalidClient,
|
||||
ErrorDescription: "client_secret is invalid",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// check whether the refresh token is valid, and has not expired.
|
||||
token, err := GetTokenByRefreshToken(refreshToken)
|
||||
if err != nil || token == nil {
|
||||
return &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "refresh token is invalid, expired or revoked",
|
||||
}, nil
|
||||
}
|
||||
|
||||
cert, err := getCertByApplication(application)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cert == nil {
|
||||
return &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: fmt.Sprintf("cert: %s cannot be found", application.Cert),
|
||||
}, nil
|
||||
}
|
||||
|
||||
_, err = ParseJwtToken(refreshToken, cert)
|
||||
if err != nil {
|
||||
return &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: fmt.Sprintf("parse refresh token error: %s", err.Error()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// generate a new token
|
||||
user, err := getUser(application.Organization, token.User)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if user.IsForbidden {
|
||||
return &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "the user is forbidden to sign in, please contact the administrator",
|
||||
}, nil
|
||||
}
|
||||
|
||||
err = ExtendUserWithRolesAndPermissions(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newAccessToken, newRefreshToken, tokenName, err := generateJwtToken(application, user, "", scope, host)
|
||||
if err != nil {
|
||||
return &TokenError{
|
||||
Error: EndpointError,
|
||||
ErrorDescription: fmt.Sprintf("generate jwt token error: %s", err.Error()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
newToken := &Token{
|
||||
Owner: application.Owner,
|
||||
Name: tokenName,
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: application.Name,
|
||||
Organization: user.Owner,
|
||||
User: user.Name,
|
||||
Code: util.GenerateClientId(),
|
||||
AccessToken: newAccessToken,
|
||||
RefreshToken: newRefreshToken,
|
||||
ExpiresIn: application.ExpireInHours * hourSeconds,
|
||||
Scope: scope,
|
||||
TokenType: "Bearer",
|
||||
}
|
||||
_, err = AddToken(newToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = DeleteToken(token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tokenWrapper := &TokenWrapper{
|
||||
AccessToken: newToken.AccessToken,
|
||||
IdToken: newToken.AccessToken,
|
||||
RefreshToken: newToken.RefreshToken,
|
||||
TokenType: newToken.TokenType,
|
||||
ExpiresIn: newToken.ExpiresIn,
|
||||
Scope: newToken.Scope,
|
||||
}
|
||||
return tokenWrapper, nil
|
||||
}
|
||||
|
||||
// PkceChallenge: base64-URL-encoded SHA256 hash of verifier, per rfc 7636
|
||||
func pkceChallenge(verifier string) string {
|
||||
sum := sha256.Sum256([]byte(verifier))
|
||||
challenge := base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(sum[:])
|
||||
return challenge
|
||||
}
|
||||
|
||||
// IsGrantTypeValid
|
||||
// Check if grantType is allowed in the current application
|
||||
// authorization_code is allowed by default
|
||||
func IsGrantTypeValid(method string, grantTypes []string) bool {
|
||||
if method == "authorization_code" {
|
||||
return true
|
||||
}
|
||||
for _, m := range grantTypes {
|
||||
if m == method {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetAuthorizationCodeToken
|
||||
// Authorization code flow
|
||||
func GetAuthorizationCodeToken(application *Application, clientSecret string, code string, verifier string) (*Token, *TokenError, error) {
|
||||
if code == "" {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidRequest,
|
||||
ErrorDescription: "authorization code should not be empty",
|
||||
}, nil
|
||||
}
|
||||
|
||||
token, err := getTokenByCode(code)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if token == nil {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "authorization code is invalid",
|
||||
}, nil
|
||||
}
|
||||
if token.CodeIsUsed {
|
||||
// anti replay attacks
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "authorization code has been used",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if token.CodeChallenge != "" && pkceChallenge(verifier) != token.CodeChallenge {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "verifier is invalid",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if application.ClientSecret != clientSecret {
|
||||
// when using PKCE, the Client Secret can be empty,
|
||||
// but if it is provided, it must be accurate.
|
||||
if token.CodeChallenge == "" {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidClient,
|
||||
ErrorDescription: "client_secret is invalid",
|
||||
}, nil
|
||||
} else {
|
||||
if clientSecret != "" {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidClient,
|
||||
ErrorDescription: "client_secret is invalid",
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if application.Name != token.Application {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "the token is for wrong application (client_id)",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if time.Now().Unix() > token.CodeExpireIn {
|
||||
// code must be used within 5 minutes
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "authorization code has expired",
|
||||
}, nil
|
||||
}
|
||||
return token, nil, nil
|
||||
}
|
||||
|
||||
// GetPasswordToken
|
||||
// Resource Owner Password Credentials flow
|
||||
func GetPasswordToken(application *Application, username string, password string, scope string, host string) (*Token, *TokenError, error) {
|
||||
user, err := getUser(application.Organization, username)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if user == nil {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "the user does not exist",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if user.Ldap != "" {
|
||||
err = checkLdapUserPassword(user, password, "en")
|
||||
} else {
|
||||
err = CheckPassword(user, password, "en")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: fmt.Sprintf("invalid username or password: %s", err.Error()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
if user.IsForbidden {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "the user is forbidden to sign in, please contact the administrator",
|
||||
}, nil
|
||||
}
|
||||
|
||||
err = ExtendUserWithRolesAndPermissions(user)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", scope, host)
|
||||
if err != nil {
|
||||
return nil, &TokenError{
|
||||
Error: EndpointError,
|
||||
ErrorDescription: fmt.Sprintf("generate jwt token error: %s", err.Error()),
|
||||
}, nil
|
||||
}
|
||||
token := &Token{
|
||||
Owner: application.Owner,
|
||||
Name: tokenName,
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: application.Name,
|
||||
Organization: user.Owner,
|
||||
User: user.Name,
|
||||
Code: util.GenerateClientId(),
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: application.ExpireInHours * hourSeconds,
|
||||
Scope: scope,
|
||||
TokenType: "Bearer",
|
||||
CodeIsUsed: true,
|
||||
}
|
||||
_, err = AddToken(token)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return token, nil, nil
|
||||
}
|
||||
|
||||
// GetClientCredentialsToken
|
||||
// Client Credentials flow
|
||||
func GetClientCredentialsToken(application *Application, clientSecret string, scope string, host string) (*Token, *TokenError, error) {
|
||||
if application.ClientSecret != clientSecret {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidClient,
|
||||
ErrorDescription: "client_secret is invalid",
|
||||
}, nil
|
||||
}
|
||||
nullUser := &User{
|
||||
Owner: application.Owner,
|
||||
Id: application.GetId(),
|
||||
Name: application.Name,
|
||||
Type: "application",
|
||||
}
|
||||
|
||||
accessToken, _, tokenName, err := generateJwtToken(application, nullUser, "", scope, host)
|
||||
if err != nil {
|
||||
return nil, &TokenError{
|
||||
Error: EndpointError,
|
||||
ErrorDescription: fmt.Sprintf("generate jwt token error: %s", err.Error()),
|
||||
}, nil
|
||||
}
|
||||
token := &Token{
|
||||
Owner: application.Owner,
|
||||
Name: tokenName,
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: application.Name,
|
||||
Organization: application.Organization,
|
||||
User: nullUser.Name,
|
||||
Code: util.GenerateClientId(),
|
||||
AccessToken: accessToken,
|
||||
ExpiresIn: application.ExpireInHours * hourSeconds,
|
||||
Scope: scope,
|
||||
TokenType: "Bearer",
|
||||
CodeIsUsed: true,
|
||||
}
|
||||
_, err = AddToken(token)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return token, nil, nil
|
||||
}
|
||||
|
||||
// GetTokenByUser
|
||||
// Implicit flow
|
||||
func GetTokenByUser(application *Application, user *User, scope string, nonce string, host string) (*Token, error) {
|
||||
err := ExtendUserWithRolesAndPermissions(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, nonce, scope, host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
token := &Token{
|
||||
Owner: application.Owner,
|
||||
Name: tokenName,
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: application.Name,
|
||||
Organization: user.Owner,
|
||||
User: user.Name,
|
||||
Code: util.GenerateClientId(),
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: application.ExpireInHours * hourSeconds,
|
||||
Scope: scope,
|
||||
TokenType: "Bearer",
|
||||
CodeIsUsed: true,
|
||||
}
|
||||
_, err = AddToken(token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// GetWechatMiniProgramToken
|
||||
// Wechat Mini Program flow
|
||||
func GetWechatMiniProgramToken(application *Application, code string, host string, username string, avatar string, lang string) (*Token, *TokenError, error) {
|
||||
mpProvider := GetWechatMiniProgramProvider(application)
|
||||
if mpProvider == nil {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidClient,
|
||||
ErrorDescription: "the application does not support wechat mini program",
|
||||
}, nil
|
||||
}
|
||||
provider, err := GetProvider(util.GetId("admin", mpProvider.Name))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
mpIdp := idp.NewWeChatMiniProgramIdProvider(provider.ClientId, provider.ClientSecret)
|
||||
session, err := mpIdp.GetSessionByCode(code)
|
||||
if err != nil {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: fmt.Sprintf("get wechat mini program session error: %s", err.Error()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
openId, unionId := session.Openid, session.Unionid
|
||||
if openId == "" && unionId == "" {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidRequest,
|
||||
ErrorDescription: "the wechat mini program session is invalid",
|
||||
}, nil
|
||||
}
|
||||
user, err := getUserByWechatId(application.Organization, openId, unionId)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
if !application.EnableSignUp {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "the application does not allow to sign up new account",
|
||||
}, nil
|
||||
}
|
||||
// Add new user
|
||||
var name string
|
||||
if CheckUsername(username, lang) == "" {
|
||||
name = username
|
||||
} else {
|
||||
name = fmt.Sprintf("wechat-%s", openId)
|
||||
}
|
||||
|
||||
user = &User{
|
||||
Owner: application.Organization,
|
||||
Id: util.GenerateId(),
|
||||
Name: name,
|
||||
Avatar: avatar,
|
||||
SignupApplication: application.Name,
|
||||
WeChat: openId,
|
||||
Type: "normal-user",
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
IsAdmin: false,
|
||||
IsForbidden: false,
|
||||
IsDeleted: false,
|
||||
Properties: map[string]string{
|
||||
UserPropertiesWechatOpenId: openId,
|
||||
UserPropertiesWechatUnionId: unionId,
|
||||
},
|
||||
}
|
||||
_, err = AddUser(user)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = ExtendUserWithRolesAndPermissions(user)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", "", host)
|
||||
if err != nil {
|
||||
return nil, &TokenError{
|
||||
Error: EndpointError,
|
||||
ErrorDescription: fmt.Sprintf("generate jwt token error: %s", err.Error()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
token := &Token{
|
||||
Owner: application.Owner,
|
||||
Name: tokenName,
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: application.Name,
|
||||
Organization: user.Owner,
|
||||
User: user.Name,
|
||||
Code: session.SessionKey, // a trick, because miniprogram does not use the code, so use the code field to save the session_key
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: application.ExpireInHours * 60,
|
||||
Scope: "",
|
||||
TokenType: "Bearer",
|
||||
CodeIsUsed: true,
|
||||
}
|
||||
_, err = AddToken(token)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return token, nil, nil
|
||||
}
|
||||
|
@ -256,12 +256,12 @@ func GetValidationBySaml(samlRequest string, host string) (string, string, error
|
||||
|
||||
ticket := request.AssertionArtifact.InnerXML
|
||||
if ticket == "" {
|
||||
return "", "", fmt.Errorf("samlp:AssertionArtifact field not found")
|
||||
return "", "", fmt.Errorf("request.AssertionArtifact.InnerXML error, AssertionArtifact field not found")
|
||||
}
|
||||
|
||||
ok, _, service, userId := GetCasTokenByTicket(ticket)
|
||||
if !ok {
|
||||
return "", "", fmt.Errorf("ticket %s found", ticket)
|
||||
return "", "", fmt.Errorf("the CAS token for ticket %s is not found", ticket)
|
||||
}
|
||||
|
||||
user, err := GetUser(userId)
|
||||
@ -270,7 +270,7 @@ func GetValidationBySaml(samlRequest string, host string) (string, string, error
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
return "", "", fmt.Errorf("user %s found", userId)
|
||||
return "", "", fmt.Errorf("the user %s is not found", userId)
|
||||
}
|
||||
|
||||
application, err := GetApplicationByUser(user)
|
||||
@ -279,10 +279,13 @@ func GetValidationBySaml(samlRequest string, host string) (string, string, error
|
||||
}
|
||||
|
||||
if application == nil {
|
||||
return "", "", fmt.Errorf("application for user %s found", userId)
|
||||
return "", "", fmt.Errorf("the application for user %s is not found", userId)
|
||||
}
|
||||
|
||||
samlResponse := NewSamlResponse11(user, request.RequestID, host)
|
||||
samlResponse, err := NewSamlResponse11(user, request.RequestID, host)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
cert, err := getCertByApplication(application)
|
||||
if err != nil {
|
||||
|
@ -40,7 +40,7 @@ type UserShort struct {
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
Avatar string `xorm:"varchar(500)" json:"avatar"`
|
||||
Email string `xorm:"varchar(100) index" json:"email"`
|
||||
Phone string `xorm:"varchar(20) index" json:"phone"`
|
||||
Phone string `xorm:"varchar(100) index" json:"phone"`
|
||||
}
|
||||
|
||||
type UserWithoutThirdIdp struct {
|
||||
@ -48,10 +48,11 @@ type UserWithoutThirdIdp struct {
|
||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||
CreatedTime string `xorm:"varchar(100) index" json:"createdTime"`
|
||||
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
|
||||
DeletedTime string `xorm:"varchar(100)" json:"deletedTime"`
|
||||
|
||||
Id string `xorm:"varchar(100) index" json:"id"`
|
||||
Type string `xorm:"varchar(100)" json:"type"`
|
||||
Password string `xorm:"varchar(100)" json:"password"`
|
||||
Password string `xorm:"varchar(150)" json:"password"`
|
||||
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
|
||||
PasswordType string `xorm:"varchar(100)" json:"passwordType"`
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
@ -62,7 +63,7 @@ type UserWithoutThirdIdp struct {
|
||||
PermanentAvatar string `xorm:"varchar(500)" json:"permanentAvatar"`
|
||||
Email string `xorm:"varchar(100) index" json:"email"`
|
||||
EmailVerified bool `json:"emailVerified"`
|
||||
Phone string `xorm:"varchar(20) index" json:"phone"`
|
||||
Phone string `xorm:"varchar(100) index" json:"phone"`
|
||||
CountryCode string `xorm:"varchar(6)" json:"countryCode"`
|
||||
Region string `xorm:"varchar(100)" json:"region"`
|
||||
Location string `xorm:"varchar(100)" json:"location"`
|
||||
@ -167,6 +168,7 @@ func getUserWithoutThirdIdp(user *User) *UserWithoutThirdIdp {
|
||||
Name: user.Name,
|
||||
CreatedTime: user.CreatedTime,
|
||||
UpdatedTime: user.UpdatedTime,
|
||||
DeletedTime: user.DeletedTime,
|
||||
|
||||
Id: user.Id,
|
||||
Type: user.Type,
|
||||
@ -357,6 +359,10 @@ func generateJwtToken(application *Application, user *User, nonce string, scope
|
||||
var token *jwt.Token
|
||||
var refreshToken *jwt.Token
|
||||
|
||||
if application.TokenFormat == "" {
|
||||
application.TokenFormat = "JWT"
|
||||
}
|
||||
|
||||
// the JWT token length in "JWT-Empty" mode will be very short, as User object only has two properties: owner and name
|
||||
if application.TokenFormat == "JWT" {
|
||||
claimsWithoutThirdIdp := getClaimsWithoutThirdIdp(claims)
|
||||
|
@ -15,16 +15,19 @@
|
||||
package object
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
)
|
||||
|
||||
func generateRsaKeys(bitSize int, expireInYears int, commonName string, organization string) (string, string, error) {
|
||||
func generateRsaKeys(bitSize int, shaSize int, expireInYears int, commonName string, organization string) (string, string, error) {
|
||||
// https://stackoverflow.com/questions/64104586/use-golang-to-get-rsa-key-the-same-way-openssl-genrsa
|
||||
// https://stackoverflow.com/questions/43822945/golang-can-i-create-x509keypair-using-rsa-key
|
||||
|
||||
@ -55,6 +58,132 @@ func generateRsaKeys(bitSize int, expireInYears int, commonName string, organiza
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
|
||||
switch shaSize {
|
||||
case 256:
|
||||
tml.SignatureAlgorithm = x509.SHA256WithRSA
|
||||
case 384:
|
||||
tml.SignatureAlgorithm = x509.SHA384WithRSA
|
||||
case 512:
|
||||
tml.SignatureAlgorithm = x509.SHA512WithRSA
|
||||
default:
|
||||
return "", "", fmt.Errorf("generateRsaKeys() error, unsupported SHA size: %d", shaSize)
|
||||
}
|
||||
|
||||
cert, err := x509.CreateCertificate(rand.Reader, &tml, &tml, &key.PublicKey, key)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
// Generate a pem block with the certificate
|
||||
certPem := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: cert,
|
||||
})
|
||||
|
||||
return string(certPem), string(privateKeyPem), nil
|
||||
}
|
||||
|
||||
func generateEsKeys(shaSize int, expireInYears int, commonName string, organization string) (string, string, error) {
|
||||
var curve elliptic.Curve
|
||||
switch shaSize {
|
||||
case 256:
|
||||
curve = elliptic.P256()
|
||||
case 384:
|
||||
curve = elliptic.P384()
|
||||
case 512:
|
||||
curve = elliptic.P521() // ES512(P521,SHA512)
|
||||
default:
|
||||
return "", "", fmt.Errorf("generateEsKeys() error, unsupported SHA size: %d", shaSize)
|
||||
}
|
||||
|
||||
// Generate ECDSA key pair.
|
||||
privateKey, err := ecdsa.GenerateKey(curve, rand.Reader)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
// Encode private key to PEM format.
|
||||
privateKeyBytes, err := x509.MarshalECPrivateKey(privateKey)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
privateKeyPem := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "EC PRIVATE KEY",
|
||||
Bytes: privateKeyBytes,
|
||||
})
|
||||
|
||||
// Generate certificate template.
|
||||
template := x509.Certificate{
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().AddDate(expireInYears, 0, 0),
|
||||
SerialNumber: big.NewInt(time.Now().Unix()),
|
||||
Subject: pkix.Name{
|
||||
CommonName: commonName,
|
||||
Organization: []string{organization},
|
||||
},
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
|
||||
// Generate certificate.
|
||||
certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
// Encode certificate to PEM format.
|
||||
certPem := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: certBytes,
|
||||
})
|
||||
|
||||
return string(certPem), string(privateKeyPem), nil
|
||||
}
|
||||
|
||||
func generateRsaPssKeys(bitSize int, shaSize int, expireInYears int, commonName string, organization string) (string, string, error) {
|
||||
// Generate RSA key.
|
||||
key, err := rsa.GenerateKey(rand.Reader, bitSize)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
// Encode private key to PKCS#8 ASN.1 PEM.
|
||||
privateKeyBytes, err := x509.MarshalPKCS8PrivateKey(key)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
privateKeyPem := pem.EncodeToMemory(
|
||||
&pem.Block{
|
||||
Type: "RSA PSS PRIVATE KEY",
|
||||
Bytes: privateKeyBytes,
|
||||
},
|
||||
)
|
||||
|
||||
tml := x509.Certificate{
|
||||
// you can add any attr that you need
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().AddDate(expireInYears, 0, 0),
|
||||
// you have to generate a different serial number each execution
|
||||
SerialNumber: big.NewInt(123456),
|
||||
Subject: pkix.Name{
|
||||
CommonName: commonName,
|
||||
Organization: []string{organization},
|
||||
},
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
|
||||
// Set the signature algorithm based on the hash function
|
||||
switch shaSize {
|
||||
case 256:
|
||||
tml.SignatureAlgorithm = x509.SHA256WithRSAPSS
|
||||
case 384:
|
||||
tml.SignatureAlgorithm = x509.SHA384WithRSAPSS
|
||||
case 512:
|
||||
tml.SignatureAlgorithm = x509.SHA512WithRSAPSS
|
||||
default:
|
||||
return "", "", fmt.Errorf("generateRsaPssKeys() error, unsupported SHA size: %d", shaSize)
|
||||
}
|
||||
|
||||
cert, err := x509.CreateCertificate(rand.Reader, &tml, &tml, &key.PublicKey, key)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
|
@ -23,7 +23,35 @@ import (
|
||||
|
||||
func TestGenerateRsaKeys(t *testing.T) {
|
||||
fileId := "token_jwt_key"
|
||||
certificate, privateKey, err := generateRsaKeys(4096, 20, "Casdoor Cert", "Casdoor Organization")
|
||||
certificate, privateKey, err := generateRsaKeys(4096, 512, 20, "Casdoor Cert", "Casdoor Organization")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Write certificate (aka certificate) to file.
|
||||
util.WriteStringToPath(certificate, fmt.Sprintf("%s.pem", fileId))
|
||||
|
||||
// Write private key to file.
|
||||
util.WriteStringToPath(privateKey, fmt.Sprintf("%s.key", fileId))
|
||||
}
|
||||
|
||||
func TestGenerateEsKeys(t *testing.T) {
|
||||
fileId := "token_jwt_key"
|
||||
certificate, privateKey, err := generateEsKeys(256, 20, "Casdoor Cert", "Casdoor Organization")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Write certificate (aka certificate) to file.
|
||||
util.WriteStringToPath(certificate, fmt.Sprintf("%s.pem", fileId))
|
||||
|
||||
// Write private key to file.
|
||||
util.WriteStringToPath(privateKey, fmt.Sprintf("%s.key", fileId))
|
||||
}
|
||||
|
||||
func TestGenerateRsaPssKeys(t *testing.T) {
|
||||
fileId := "token_jwt_key"
|
||||
certificate, privateKey, err := generateRsaPssKeys(4096, 256, 20, "Casdoor Cert", "Casdoor Organization")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
774
object/token_oauth.go
Normal file
774
object/token_oauth.go
Normal file
@ -0,0 +1,774 @@
|
||||
// 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 (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/casdoor/casdoor/i18n"
|
||||
"github.com/casdoor/casdoor/idp"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/xorm-io/core"
|
||||
)
|
||||
|
||||
const (
|
||||
hourSeconds = int(time.Hour / time.Second)
|
||||
InvalidRequest = "invalid_request"
|
||||
InvalidClient = "invalid_client"
|
||||
InvalidGrant = "invalid_grant"
|
||||
UnauthorizedClient = "unauthorized_client"
|
||||
UnsupportedGrantType = "unsupported_grant_type"
|
||||
InvalidScope = "invalid_scope"
|
||||
EndpointError = "endpoint_error"
|
||||
)
|
||||
|
||||
type Code struct {
|
||||
Message string `xorm:"varchar(100)" json:"message"`
|
||||
Code string `xorm:"varchar(100)" json:"code"`
|
||||
}
|
||||
|
||||
type TokenWrapper struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
IdToken string `json:"id_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
Scope string `json:"scope"`
|
||||
}
|
||||
|
||||
type TokenError struct {
|
||||
Error string `json:"error"`
|
||||
ErrorDescription string `json:"error_description,omitempty"`
|
||||
}
|
||||
|
||||
type IntrospectionResponse struct {
|
||||
Active bool `json:"active"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
ClientId string `json:"client_id,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
TokenType string `json:"token_type,omitempty"`
|
||||
Exp int64 `json:"exp,omitempty"`
|
||||
Iat int64 `json:"iat,omitempty"`
|
||||
Nbf int64 `json:"nbf,omitempty"`
|
||||
Sub string `json:"sub,omitempty"`
|
||||
Aud []string `json:"aud,omitempty"`
|
||||
Iss string `json:"iss,omitempty"`
|
||||
Jti string `json:"jti,omitempty"`
|
||||
}
|
||||
|
||||
func ExpireTokenByAccessToken(accessToken string) (bool, *Application, *Token, error) {
|
||||
token, err := GetTokenByAccessToken(accessToken)
|
||||
if err != nil {
|
||||
return false, nil, nil, err
|
||||
}
|
||||
if token == nil {
|
||||
return false, nil, nil, nil
|
||||
}
|
||||
|
||||
token.ExpiresIn = 0
|
||||
affected, err := ormer.Engine.ID(core.PK{token.Owner, token.Name}).Cols("expires_in").Update(token)
|
||||
if err != nil {
|
||||
return false, nil, nil, err
|
||||
}
|
||||
|
||||
application, err := getApplication(token.Owner, token.Application)
|
||||
if err != nil {
|
||||
return false, nil, nil, err
|
||||
}
|
||||
|
||||
return affected != 0, application, token, nil
|
||||
}
|
||||
|
||||
func CheckOAuthLogin(clientId string, responseType string, redirectUri string, scope string, state string, lang string) (string, *Application, error) {
|
||||
if responseType != "code" && responseType != "token" && responseType != "id_token" {
|
||||
return fmt.Sprintf(i18n.Translate(lang, "token:Grant_type: %s is not supported in this application"), responseType), nil, nil
|
||||
}
|
||||
|
||||
application, err := GetApplicationByClientId(clientId)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if application == nil {
|
||||
return i18n.Translate(lang, "token:Invalid client_id"), nil, nil
|
||||
}
|
||||
|
||||
if !application.IsRedirectUriValid(redirectUri) {
|
||||
return fmt.Sprintf(i18n.Translate(lang, "token:Redirect URI: %s doesn't exist in the allowed Redirect URI list"), redirectUri), application, nil
|
||||
}
|
||||
|
||||
// Mask application for /api/get-app-login
|
||||
application.ClientSecret = ""
|
||||
return "", application, nil
|
||||
}
|
||||
|
||||
func GetOAuthCode(userId string, clientId string, responseType string, redirectUri string, scope string, state string, nonce string, challenge string, host string, lang string) (*Code, error) {
|
||||
user, err := GetUser(userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
return &Code{
|
||||
Message: fmt.Sprintf("general:The user: %s doesn't exist", userId),
|
||||
Code: "",
|
||||
}, nil
|
||||
}
|
||||
if user.IsForbidden {
|
||||
return &Code{
|
||||
Message: "error: the user is forbidden to sign in, please contact the administrator",
|
||||
Code: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
msg, application, err := CheckOAuthLogin(clientId, responseType, redirectUri, scope, state, lang)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if msg != "" {
|
||||
return &Code{
|
||||
Message: msg,
|
||||
Code: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
err = ExtendUserWithRolesAndPermissions(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, nonce, scope, host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if challenge == "null" {
|
||||
challenge = ""
|
||||
}
|
||||
|
||||
token := &Token{
|
||||
Owner: application.Owner,
|
||||
Name: tokenName,
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: application.Name,
|
||||
Organization: user.Owner,
|
||||
User: user.Name,
|
||||
Code: util.GenerateClientId(),
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: application.ExpireInHours * hourSeconds,
|
||||
Scope: scope,
|
||||
TokenType: "Bearer",
|
||||
CodeChallenge: challenge,
|
||||
CodeIsUsed: false,
|
||||
CodeExpireIn: time.Now().Add(time.Minute * 5).Unix(),
|
||||
}
|
||||
_, err = AddToken(token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Code{
|
||||
Message: "",
|
||||
Code: token.Code,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func GetOAuthToken(grantType string, clientId string, clientSecret string, code string, verifier string, scope string, nonce string, username string, password string, host string, refreshToken string, tag string, avatar string, lang string) (interface{}, error) {
|
||||
application, err := GetApplicationByClientId(clientId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if application == nil {
|
||||
return &TokenError{
|
||||
Error: InvalidClient,
|
||||
ErrorDescription: "client_id is invalid",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Check if grantType is allowed in the current application
|
||||
|
||||
if !IsGrantTypeValid(grantType, application.GrantTypes) && tag == "" {
|
||||
return &TokenError{
|
||||
Error: UnsupportedGrantType,
|
||||
ErrorDescription: fmt.Sprintf("grant_type: %s is not supported in this application", grantType),
|
||||
}, nil
|
||||
}
|
||||
|
||||
var token *Token
|
||||
var tokenError *TokenError
|
||||
switch grantType {
|
||||
case "authorization_code": // Authorization Code Grant
|
||||
token, tokenError, err = GetAuthorizationCodeToken(application, clientSecret, code, verifier)
|
||||
case "password": // Resource Owner Password Credentials Grant
|
||||
token, tokenError, err = GetPasswordToken(application, username, password, scope, host)
|
||||
case "client_credentials": // Client Credentials Grant
|
||||
token, tokenError, err = GetClientCredentialsToken(application, clientSecret, scope, host)
|
||||
case "token", "id_token": // Implicit Grant
|
||||
token, tokenError, err = GetImplicitToken(application, username, scope, nonce, host)
|
||||
case "refresh_token":
|
||||
refreshToken2, err := RefreshToken(grantType, refreshToken, scope, clientId, clientSecret, host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return refreshToken2, nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if tag == "wechat_miniprogram" {
|
||||
// Wechat Mini Program
|
||||
token, tokenError, err = GetWechatMiniProgramToken(application, code, host, username, avatar, lang)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if tokenError != nil {
|
||||
return tokenError, nil
|
||||
}
|
||||
|
||||
token.CodeIsUsed = true
|
||||
|
||||
go updateUsedByCode(token)
|
||||
|
||||
tokenWrapper := &TokenWrapper{
|
||||
AccessToken: token.AccessToken,
|
||||
IdToken: token.AccessToken,
|
||||
RefreshToken: token.RefreshToken,
|
||||
TokenType: token.TokenType,
|
||||
ExpiresIn: token.ExpiresIn,
|
||||
Scope: token.Scope,
|
||||
}
|
||||
|
||||
return tokenWrapper, nil
|
||||
}
|
||||
|
||||
func RefreshToken(grantType string, refreshToken string, scope string, clientId string, clientSecret string, host string) (interface{}, error) {
|
||||
// check parameters
|
||||
if grantType != "refresh_token" {
|
||||
return &TokenError{
|
||||
Error: UnsupportedGrantType,
|
||||
ErrorDescription: "grant_type should be refresh_token",
|
||||
}, nil
|
||||
}
|
||||
application, err := GetApplicationByClientId(clientId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if application == nil {
|
||||
return &TokenError{
|
||||
Error: InvalidClient,
|
||||
ErrorDescription: "client_id is invalid",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if clientSecret != "" && application.ClientSecret != clientSecret {
|
||||
return &TokenError{
|
||||
Error: InvalidClient,
|
||||
ErrorDescription: "client_secret is invalid",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// check whether the refresh token is valid, and has not expired.
|
||||
token, err := GetTokenByRefreshToken(refreshToken)
|
||||
if err != nil || token == nil {
|
||||
return &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "refresh token is invalid, expired or revoked",
|
||||
}, nil
|
||||
}
|
||||
|
||||
cert, err := getCertByApplication(application)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cert == nil {
|
||||
return &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: fmt.Sprintf("cert: %s cannot be found", application.Cert),
|
||||
}, nil
|
||||
}
|
||||
|
||||
_, err = ParseJwtToken(refreshToken, cert)
|
||||
if err != nil {
|
||||
return &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: fmt.Sprintf("parse refresh token error: %s", err.Error()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// generate a new token
|
||||
user, err := getUser(application.Organization, token.User)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if user.IsForbidden {
|
||||
return &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "the user is forbidden to sign in, please contact the administrator",
|
||||
}, nil
|
||||
}
|
||||
|
||||
err = ExtendUserWithRolesAndPermissions(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newAccessToken, newRefreshToken, tokenName, err := generateJwtToken(application, user, "", scope, host)
|
||||
if err != nil {
|
||||
return &TokenError{
|
||||
Error: EndpointError,
|
||||
ErrorDescription: fmt.Sprintf("generate jwt token error: %s", err.Error()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
newToken := &Token{
|
||||
Owner: application.Owner,
|
||||
Name: tokenName,
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: application.Name,
|
||||
Organization: user.Owner,
|
||||
User: user.Name,
|
||||
Code: util.GenerateClientId(),
|
||||
AccessToken: newAccessToken,
|
||||
RefreshToken: newRefreshToken,
|
||||
ExpiresIn: application.ExpireInHours * hourSeconds,
|
||||
Scope: scope,
|
||||
TokenType: "Bearer",
|
||||
}
|
||||
_, err = AddToken(newToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = DeleteToken(token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tokenWrapper := &TokenWrapper{
|
||||
AccessToken: newToken.AccessToken,
|
||||
IdToken: newToken.AccessToken,
|
||||
RefreshToken: newToken.RefreshToken,
|
||||
TokenType: newToken.TokenType,
|
||||
ExpiresIn: newToken.ExpiresIn,
|
||||
Scope: newToken.Scope,
|
||||
}
|
||||
return tokenWrapper, nil
|
||||
}
|
||||
|
||||
// PkceChallenge: base64-URL-encoded SHA256 hash of verifier, per rfc 7636
|
||||
func pkceChallenge(verifier string) string {
|
||||
sum := sha256.Sum256([]byte(verifier))
|
||||
challenge := base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(sum[:])
|
||||
return challenge
|
||||
}
|
||||
|
||||
// IsGrantTypeValid
|
||||
// Check if grantType is allowed in the current application
|
||||
// authorization_code is allowed by default
|
||||
func IsGrantTypeValid(method string, grantTypes []string) bool {
|
||||
if method == "authorization_code" {
|
||||
return true
|
||||
}
|
||||
for _, m := range grantTypes {
|
||||
if m == method {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetAuthorizationCodeToken
|
||||
// Authorization code flow
|
||||
func GetAuthorizationCodeToken(application *Application, clientSecret string, code string, verifier string) (*Token, *TokenError, error) {
|
||||
if code == "" {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidRequest,
|
||||
ErrorDescription: "authorization code should not be empty",
|
||||
}, nil
|
||||
}
|
||||
|
||||
token, err := getTokenByCode(code)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if token == nil {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "authorization code is invalid",
|
||||
}, nil
|
||||
}
|
||||
if token.CodeIsUsed {
|
||||
// anti replay attacks
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "authorization code has been used",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if token.CodeChallenge != "" && pkceChallenge(verifier) != token.CodeChallenge {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "verifier is invalid",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if application.ClientSecret != clientSecret {
|
||||
// when using PKCE, the Client Secret can be empty,
|
||||
// but if it is provided, it must be accurate.
|
||||
if token.CodeChallenge == "" {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidClient,
|
||||
ErrorDescription: "client_secret is invalid",
|
||||
}, nil
|
||||
} else {
|
||||
if clientSecret != "" {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidClient,
|
||||
ErrorDescription: "client_secret is invalid",
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if application.Name != token.Application {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "the token is for wrong application (client_id)",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if time.Now().Unix() > token.CodeExpireIn {
|
||||
// code must be used within 5 minutes
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "authorization code has expired",
|
||||
}, nil
|
||||
}
|
||||
return token, nil, nil
|
||||
}
|
||||
|
||||
// GetPasswordToken
|
||||
// Resource Owner Password Credentials flow
|
||||
func GetPasswordToken(application *Application, username string, password string, scope string, host string) (*Token, *TokenError, error) {
|
||||
user, err := GetUserByFields(application.Organization, username)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if user == nil {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "the user does not exist",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if user.Ldap != "" {
|
||||
err = checkLdapUserPassword(user, password, "en")
|
||||
} else {
|
||||
err = CheckPassword(user, password, "en")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: fmt.Sprintf("invalid username or password: %s", err.Error()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
if user.IsForbidden {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "the user is forbidden to sign in, please contact the administrator",
|
||||
}, nil
|
||||
}
|
||||
|
||||
err = ExtendUserWithRolesAndPermissions(user)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", scope, host)
|
||||
if err != nil {
|
||||
return nil, &TokenError{
|
||||
Error: EndpointError,
|
||||
ErrorDescription: fmt.Sprintf("generate jwt token error: %s", err.Error()),
|
||||
}, nil
|
||||
}
|
||||
token := &Token{
|
||||
Owner: application.Owner,
|
||||
Name: tokenName,
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: application.Name,
|
||||
Organization: user.Owner,
|
||||
User: user.Name,
|
||||
Code: util.GenerateClientId(),
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: application.ExpireInHours * hourSeconds,
|
||||
Scope: scope,
|
||||
TokenType: "Bearer",
|
||||
CodeIsUsed: true,
|
||||
}
|
||||
_, err = AddToken(token)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return token, nil, nil
|
||||
}
|
||||
|
||||
// GetClientCredentialsToken
|
||||
// Client Credentials flow
|
||||
func GetClientCredentialsToken(application *Application, clientSecret string, scope string, host string) (*Token, *TokenError, error) {
|
||||
if application.ClientSecret != clientSecret {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidClient,
|
||||
ErrorDescription: "client_secret is invalid",
|
||||
}, nil
|
||||
}
|
||||
nullUser := &User{
|
||||
Owner: application.Owner,
|
||||
Id: application.GetId(),
|
||||
Name: application.Name,
|
||||
Type: "application",
|
||||
}
|
||||
|
||||
accessToken, _, tokenName, err := generateJwtToken(application, nullUser, "", scope, host)
|
||||
if err != nil {
|
||||
return nil, &TokenError{
|
||||
Error: EndpointError,
|
||||
ErrorDescription: fmt.Sprintf("generate jwt token error: %s", err.Error()),
|
||||
}, nil
|
||||
}
|
||||
token := &Token{
|
||||
Owner: application.Owner,
|
||||
Name: tokenName,
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: application.Name,
|
||||
Organization: application.Organization,
|
||||
User: nullUser.Name,
|
||||
Code: util.GenerateClientId(),
|
||||
AccessToken: accessToken,
|
||||
ExpiresIn: application.ExpireInHours * hourSeconds,
|
||||
Scope: scope,
|
||||
TokenType: "Bearer",
|
||||
CodeIsUsed: true,
|
||||
}
|
||||
_, err = AddToken(token)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return token, nil, nil
|
||||
}
|
||||
|
||||
// GetImplicitToken
|
||||
// Implicit flow
|
||||
func GetImplicitToken(application *Application, username string, scope string, nonce string, host string) (*Token, *TokenError, error) {
|
||||
user, err := GetUserByFields(application.Organization, username)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if user == nil {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "the user does not exist",
|
||||
}, nil
|
||||
}
|
||||
if user.IsForbidden {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "the user is forbidden to sign in, please contact the administrator",
|
||||
}, nil
|
||||
}
|
||||
|
||||
token, err := GetTokenByUser(application, user, scope, nonce, host)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return token, nil, nil
|
||||
}
|
||||
|
||||
// GetTokenByUser
|
||||
// Implicit flow
|
||||
func GetTokenByUser(application *Application, user *User, scope string, nonce string, host string) (*Token, error) {
|
||||
err := ExtendUserWithRolesAndPermissions(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, nonce, scope, host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
token := &Token{
|
||||
Owner: application.Owner,
|
||||
Name: tokenName,
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: application.Name,
|
||||
Organization: user.Owner,
|
||||
User: user.Name,
|
||||
Code: util.GenerateClientId(),
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: application.ExpireInHours * hourSeconds,
|
||||
Scope: scope,
|
||||
TokenType: "Bearer",
|
||||
CodeIsUsed: true,
|
||||
}
|
||||
_, err = AddToken(token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// GetWechatMiniProgramToken
|
||||
// Wechat Mini Program flow
|
||||
func GetWechatMiniProgramToken(application *Application, code string, host string, username string, avatar string, lang string) (*Token, *TokenError, error) {
|
||||
mpProvider := GetWechatMiniProgramProvider(application)
|
||||
if mpProvider == nil {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidClient,
|
||||
ErrorDescription: "the application does not support wechat mini program",
|
||||
}, nil
|
||||
}
|
||||
provider, err := GetProvider(util.GetId("admin", mpProvider.Name))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
mpIdp := idp.NewWeChatMiniProgramIdProvider(provider.ClientId, provider.ClientSecret)
|
||||
session, err := mpIdp.GetSessionByCode(code)
|
||||
if err != nil {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: fmt.Sprintf("get wechat mini program session error: %s", err.Error()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
openId, unionId := session.Openid, session.Unionid
|
||||
if openId == "" && unionId == "" {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidRequest,
|
||||
ErrorDescription: "the wechat mini program session is invalid",
|
||||
}, nil
|
||||
}
|
||||
user, err := getUserByWechatId(application.Organization, openId, unionId)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
if !application.EnableSignUp {
|
||||
return nil, &TokenError{
|
||||
Error: InvalidGrant,
|
||||
ErrorDescription: "the application does not allow to sign up new account",
|
||||
}, nil
|
||||
}
|
||||
// Add new user
|
||||
var name string
|
||||
if CheckUsername(username, lang) == "" {
|
||||
name = username
|
||||
} else {
|
||||
name = fmt.Sprintf("wechat-%s", openId)
|
||||
}
|
||||
|
||||
user = &User{
|
||||
Owner: application.Organization,
|
||||
Id: util.GenerateId(),
|
||||
Name: name,
|
||||
Avatar: avatar,
|
||||
SignupApplication: application.Name,
|
||||
WeChat: openId,
|
||||
Type: "normal-user",
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
IsAdmin: false,
|
||||
IsForbidden: false,
|
||||
IsDeleted: false,
|
||||
Properties: map[string]string{
|
||||
UserPropertiesWechatOpenId: openId,
|
||||
UserPropertiesWechatUnionId: unionId,
|
||||
},
|
||||
}
|
||||
_, err = AddUser(user)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = ExtendUserWithRolesAndPermissions(user)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", "", host)
|
||||
if err != nil {
|
||||
return nil, &TokenError{
|
||||
Error: EndpointError,
|
||||
ErrorDescription: fmt.Sprintf("generate jwt token error: %s", err.Error()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
token := &Token{
|
||||
Owner: application.Owner,
|
||||
Name: tokenName,
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
Application: application.Name,
|
||||
Organization: user.Owner,
|
||||
User: user.Name,
|
||||
Code: session.SessionKey, // a trick, because miniprogram does not use the code, so use the code field to save the session_key
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: application.ExpireInHours * hourSeconds,
|
||||
Scope: "",
|
||||
TokenType: "Bearer",
|
||||
CodeIsUsed: true,
|
||||
}
|
||||
_, err = AddToken(token)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return token, nil, nil
|
||||
}
|
||||
|
||||
func GetAccessTokenByUser(user *User, host string) (string, error) {
|
||||
application, err := GetApplicationByUser(user)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if application == nil {
|
||||
return "", fmt.Errorf("the application for user %s is not found", user.Id)
|
||||
}
|
||||
|
||||
token, err := GetTokenByUser(application, user, "profile", "", host)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return token.AccessToken, nil
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user