Compare commits

...

40 Commits

Author SHA1 Message Date
3354945119 feat: add SendGrid Email provider (#2865)
* feat: add support for email provider send grid

* feat: rename send grid to sendgrid

* feat: rename send grid to sendgrid

* feat: change logo url of send grid
2024-04-09 22:16:01 +08:00
19c4416f10 feat: degrade the ant-design/cssinjs version to fix the Chrome 87 broken UI issue (#2861) 2024-04-09 09:15:39 +08:00
2077db9091 fix: fix bug in VerificationListPage 2024-04-07 15:39:25 +08:00
800f0ed249 feat: add tzdata package in Dockerfile to fix timezone issue (#2857)
Add tzdata to resolve possible time zone errors
2024-04-07 14:27:45 +08:00
xyt
6161040c67 fix: Dismiss google one tap after logged in by setting disableCancelOnUnmount to false (#2854)
* fix: Google One Tap should be hidden after logged in

* Change the call location for google.accounts.id.cancel()

* fix: hide google one tap after login by set disableCancelOnUnmount to false
2024-04-05 23:39:33 +08:00
xyt
1d785e61c6 feat: Google One Tap should be hidden after logged in (#2853)
* fix: Google One Tap should be hidden after logged in

* Change the call location for google.accounts.id.cancel()
2024-04-05 20:10:13 +08:00
0329d24867 feat: add isUsernameLowered to config 2024-04-02 21:54:16 +08:00
fb6f3623ee feat: add requireProviderPermission() 2024-03-30 23:24:59 +08:00
eb448bd043 fix: fix permission problem in provider (#2848) 2024-03-30 23:18:03 +08:00
xyt
ea88839db9 feat: add back button in forget password page (#2847)
* feat: add back button in forget password page

* fix: can't step back when directly entering forgot password page

* feat: forget password page always return to login page

* feat: if has history then go back to history & change style

* Update ForgetPage.js

* fix: reset button position

* Update ForgetPage.js

* Update ForgetPage.js

---------

Co-authored-by: Eric Luo <hsluoyz@qq.com>
2024-03-30 23:17:47 +08:00
cb95f6977a fix: fix PasswordModal error when changing username 2024-03-30 12:28:55 +08:00
9067df92a7 feat: revert "feat: Support metamask mobile login" (#2845)
This reverts commit bfa2ab63ad.
2024-03-30 00:36:25 +08:00
bfa2ab63ad feat: Support metamask mobile login (#2844) 2024-03-30 00:08:52 +08:00
505054b0eb feat: use minWidth for a better display effect in org select (#2843) 2024-03-29 15:47:27 +08:00
f95ce13b82 fix: support "Email or Phone" in signup table 2024-03-29 09:07:37 +08:00
xyt
5315f16a48 feat: can specify UI theme via /?theme=default and /?theme=dark (#2842)
* feat: set themeType through URL parameter

* Update App.js

---------

Co-authored-by: Eric Luo <hsluoyz@qq.com>
2024-03-29 00:52:18 +08:00
d054f3e001 feat: The /login/oauth/access_token api supports the token and id_token grant types. (#2836)
* In the response of the /api/get-captcha endpoint, add the parameters "owner" and "name" because these two parameters will be used when calling the /api/verify-captcha endpoint.

* The /login/oauth/access_token api supports the token and id_token grant types.
2024-03-28 00:41:54 +08:00
b158b840bd Add "new-user" to webhook event list 2024-03-27 15:23:06 +08:00
b16f1807b3 fix: fix bug in "new-user" record 2024-03-27 15:15:40 +08:00
d0cce1bf7a Order by "id" in GetPaginationRecords() 2024-03-27 15:14:41 +08:00
9892cd20ab Improve erorr message in CheckVerificationCode() 2024-03-27 15:14:20 +08:00
d1f31dd327 feat: fix linter 2024-03-26 23:24:53 +08:00
94743246a1 Improve "%{user.friendlyName}" handling 2024-03-25 21:26:36 +08:00
39ad1bc593 Add signup's object in AfterRecordMessage() 2024-03-25 21:20:33 +08:00
d97f833d2a feat: Add 'owner' and 'name' Parameters to /api/get-captcha Response for /api/verify-captcha Usage (#2834) 2024-03-25 16:34:42 +08:00
948fa911e2 feat: add users to getGroups() and getGroup() APIs 2024-03-22 23:32:30 +08:00
6073a0f63d Rename GroupListPage and GroupEditPage 2024-03-22 23:14:05 +08:00
91268bca70 Improve enableAutoSignin option UI 2024-03-22 22:55:10 +08:00
23dbb0b926 feat: add response to Records page (#2830)
* feat: add response to Records page

* feat: improve AddRecord

* feat: remove log and return err

* feat: improve record in signup and record deny

* fix: filter will generate 403 record correctly
2024-03-22 14:53:38 +08:00
97cc1f9e2b fix: delete duplicate err check in utils/validation.go (#2831) 2024-03-21 18:17:38 +08:00
8c415be7c7 feat: upgrade goth to v1.79.0 2024-03-20 19:57:15 +08:00
e87165cfc8 Upgrade go.mod versions 2024-03-20 19:51:56 +08:00
fc4fa2e8b6 feat: add verification list page and related API (#2822)
* feat: add verification list page and relevant api

* feat: improve code format

* fix: fix timestamp display error
2024-03-19 19:10:52 +08:00
44ae76503e feat: add default user mapping in custom oauth2 provider (#2819) 2024-03-18 23:01:17 +08:00
ae1634a4d5 feat: fix user cannot logout issue about bug in GetSessionToken() 2024-03-18 02:11:39 +08:00
bdf9864f69 fix: add FaceIdSigninBegin() to verify user information before face login (#2815)
* feat: add FaceIdSigninBegin() to verify user information before face login

* Update face.go

---------

Co-authored-by: Eric Luo <hsluoyz@qq.com>
2024-03-18 00:04:12 +08:00
72839d6bf5 feat: fix TokenFormat error in get-account API 2024-03-17 23:03:50 +08:00
2c4b1093ed fix: Correct expiresIn calculation for WeChat Mini Program token. (#2814) 2024-03-17 22:20:21 +08:00
d1c55d5aa7 fix: improve error message in token_cas.go 2024-03-17 22:01:49 +08:00
c8aa35c9c6 feat: add token to the page for Chrome extension (#2804)
* feat: add token to the page for Chrome extension

* Update token_oauth.go

---------

Co-authored-by: Eric Luo <hsluoyz@qq.com>
2024-03-17 22:01:28 +08:00
73 changed files with 1486 additions and 340 deletions

View File

@ -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

View File

@ -98,6 +98,7 @@ 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)

View File

@ -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"

View File

@ -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"`
@ -271,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)
@ -307,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 {
@ -353,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)
@ -433,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,
@ -519,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,

View File

@ -508,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
@ -632,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 {
@ -768,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))}
@ -879,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
@ -901,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

View File

@ -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")

View File

@ -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
View 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()
}

View File

@ -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)
}

View File

@ -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()
}

View File

@ -125,9 +125,11 @@ func (c *ApiController) SendEmail() {
return
}
userString := "Hi"
if user != nil {
content = strings.Replace(content, "%{user.friendlyName}", user.GetFriendlyName(), 1)
userString = user.GetFriendlyName()
}
content = strings.Replace(content, "%{user.friendlyName}", userString, 1)
}
}

View File

@ -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

View File

@ -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"`

View File

@ -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

View File

@ -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
View 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
}

15
go.mod
View File

@ -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.19.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

182
go.sum
View File

@ -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=
@ -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=
@ -2118,8 +2155,11 @@ golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIi
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/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
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=
@ -2177,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=
@ -2222,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=
@ -2269,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=
@ -2304,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=
@ -2421,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=
@ -2449,8 +2496,10 @@ 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/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
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=
@ -2468,8 +2517,10 @@ 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/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
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=
@ -2551,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=
@ -2568,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=
@ -2610,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=
@ -2669,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=
@ -2702,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=
@ -2873,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=
@ -2928,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=
@ -2972,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=

View File

@ -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]
}

View File

@ -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"

View File

@ -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()

View File

@ -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,17 @@ 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]
@ -63,10 +80,10 @@ func NewRecord(ctx *context.Context) *casvisorsdk.Record {
Action: action,
Language: languageCode,
Object: object,
Response: "",
Response: fmt.Sprintf("{status:\"%s\", msg:\"%s\"}", resp.Status, resp.Msg),
IsTriggered: false,
}
return &record
return &record, nil
}
func AddRecord(record *casvisorsdk.Record) bool {
@ -123,6 +140,12 @@ func GetRecords() ([]*casvisorsdk.Record, error) {
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 {
@ -142,6 +165,25 @@ func GetRecordsByField(record *casvisorsdk.Record) ([]*casvisorsdk.Record, error
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 {

View File

@ -261,7 +261,7 @@ func GetValidationBySaml(samlRequest string, host string) (string, string, error
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,7 +279,7 @@ 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, err := NewSamlResponse11(user, request.RequestID, host)

View File

@ -359,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)

View File

@ -189,7 +189,7 @@ func GetOAuthCode(userId string, clientId string, responseType string, redirectU
}, 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) {
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
@ -220,6 +220,8 @@ func GetOAuthToken(grantType string, clientId string, clientSecret string, code
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 {
@ -582,6 +584,33 @@ func GetClientCredentialsToken(application *Application, clientSecret string, sc
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) {
@ -715,7 +744,7 @@ func GetWechatMiniProgramToken(application *Application, code string, host strin
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,
ExpiresIn: application.ExpireInHours * hourSeconds,
Scope: "",
TokenType: "Bearer",
CodeIsUsed: true,
@ -726,3 +755,20 @@ func GetWechatMiniProgramToken(application *Application, code string, host strin
}
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
}

View File

@ -98,6 +98,7 @@ type User struct {
PreHash string `xorm:"varchar(100)" json:"preHash"`
AccessKey string `xorm:"varchar(100)" json:"accessKey"`
AccessSecret string `xorm:"varchar(100)" json:"accessSecret"`
AccessToken string `xorm:"mediumtext" json:"accessToken"`
CreatedIp string `xorm:"varchar(100)" json:"createdIp"`
LastSigninTime string `xorm:"varchar(100)" json:"lastSigninTime"`
@ -832,6 +833,11 @@ func AddUser(user *User) (bool, error) {
}
}
isUsernameLowered := conf.GetConfigBool("isUsernameLowered")
if isUsernameLowered {
user.Name = strings.ToLower(user.Name)
}
affected, err := ormer.Engine.Insert(user)
if err != nil {
return false, err
@ -845,6 +851,8 @@ func AddUsers(users []*User) (bool, error) {
return false, fmt.Errorf("no users are provided")
}
isUsernameLowered := conf.GetConfigBool("isUsernameLowered")
// organization := GetOrganizationByUser(users[0])
for _, user := range users {
// this function is only used for syncer or batch upload, so no need to encrypt the password
@ -868,6 +876,10 @@ func AddUsers(users []*User) (bool, error) {
return false, err
}
}
if isUsernameLowered {
user.Name = strings.ToLower(user.Name)
}
}
affected, err := ormer.Engine.Insert(users)

View File

@ -50,13 +50,13 @@ type VerificationRecord struct {
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
RemoteAddr string `xorm:"varchar(100)"`
Type string `xorm:"varchar(10)"`
User string `xorm:"varchar(100) notnull"`
Provider string `xorm:"varchar(100) notnull"`
Receiver string `xorm:"varchar(100) index notnull"`
Code string `xorm:"varchar(10) notnull"`
Time int64 `xorm:"notnull"`
RemoteAddr string `xorm:"varchar(100)" json:"remoteAddr"`
Type string `xorm:"varchar(10)" json:"type"`
User string `xorm:"varchar(100) notnull" json:"user"`
Provider string `xorm:"varchar(100) notnull" json:"provider"`
Receiver string `xorm:"varchar(100) index notnull" json:"receiver"`
Code string `xorm:"varchar(10) notnull" json:"code"`
Time int64 `xorm:"notnull" json:"time"`
IsUsed bool
}
@ -92,9 +92,12 @@ func SendVerificationCodeToEmail(organization *Organization, user *User, provide
// "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)
userString := "Hi"
if user != nil {
content = strings.Replace(content, "%{user.friendlyName}", user.GetFriendlyName(), 1)
userString = user.GetFriendlyName()
}
content = strings.Replace(content, "%{user.friendlyName}", userString, 1)
err := IsAllowSend(user, remoteAddr, provider.Category)
if err != nil {
@ -187,14 +190,17 @@ func CheckVerificationCode(dest string, code string, lang string) (*VerifyResult
return &VerifyResult{noRecordError, i18n.Translate(lang, "verification:The verification code has not been sent yet, or has already been used!")}, nil
}
timeout, err := conf.GetConfigInt64("verificationCodeTimeout")
timeoutInMinutes, err := conf.GetConfigInt64("verificationCodeTimeout")
if err != nil {
return nil, err
}
now := time.Now().Unix()
if now-record.Time > timeout*60 {
return &VerifyResult{timeoutError, fmt.Sprintf(i18n.Translate(lang, "verification:You should verify your code in %d min!"), timeout)}, nil
if now-record.Time > timeoutInMinutes*60*10 {
return &VerifyResult{noRecordError, i18n.Translate(lang, "verification:The verification code has not been sent yet!")}, nil
}
if now-record.Time > timeoutInMinutes*60 {
return &VerifyResult{timeoutError, fmt.Sprintf(i18n.Translate(lang, "verification:You should verify your code in %d min!"), timeoutInMinutes)}, nil
}
if record.Code != code {
@ -278,3 +284,62 @@ func getRandomCode(length int) string {
}
return string(result)
}
func GetVerificationCount(owner, field, value string) (int64, error) {
session := GetSession(owner, -1, -1, field, value, "", "")
return session.Count(&VerificationRecord{Owner: owner})
}
func GetVerifications(owner string) ([]*VerificationRecord, error) {
verifications := []*VerificationRecord{}
err := ormer.Engine.Desc("created_time").Find(&verifications, &VerificationRecord{Owner: owner})
if err != nil {
return nil, err
}
return verifications, nil
}
func GetUserVerifications(owner, user string) ([]*VerificationRecord, error) {
verifications := []*VerificationRecord{}
err := ormer.Engine.Desc("created_time").Find(&verifications, &VerificationRecord{Owner: owner, User: user})
if err != nil {
return nil, err
}
return verifications, nil
}
func GetPaginationVerifications(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*VerificationRecord, error) {
verifications := []*VerificationRecord{}
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
err := session.Find(&verifications, &VerificationRecord{Owner: owner})
if err != nil {
return nil, err
}
return verifications, nil
}
func getVerification(owner string, name string) (*VerificationRecord, error) {
if owner == "" || name == "" {
return nil, nil
}
verification := VerificationRecord{Owner: owner, Name: name}
existed, err := ormer.Engine.Get(&verification)
if err != nil {
return nil, err
}
if existed {
return &verification, nil
} else {
return nil, nil
}
}
func GetVerification(id string) (*VerificationRecord, error) {
owner, name := util.GetOwnerAndNameFromId(id)
return getVerification(owner, name)
}

View File

@ -20,6 +20,8 @@ import (
"net/http"
"strings"
"github.com/casdoor/casdoor/object"
"github.com/beego/beego/context"
"github.com/casdoor/casdoor/authz"
"github.com/casdoor/casdoor/util"
@ -211,5 +213,17 @@ func ApiFilter(ctx *context.Context) {
if !isAllowed {
denyRequest(ctx)
record, err := object.NewRecord(ctx)
if err != nil {
return
}
record.Organization = subOwner
record.User = subName // auth:Unauthorized operation
record.Response = fmt.Sprintf("{status:\"error\", msg:\"%s\"}", T(ctx, "auth:Unauthorized operation"))
util.SafeGoroutine(func() {
object.AddRecord(record)
})
}
}

View File

@ -15,9 +15,12 @@
package routers
import (
"fmt"
"github.com/beego/beego/context"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
"github.com/casvisor/casvisor-go-sdk/casvisorsdk"
)
func getUser(ctx *context.Context) (username string) {
@ -60,12 +63,49 @@ func RecordMessage(ctx *context.Context) {
return
}
record := object.NewRecord(ctx)
userId := getUser(ctx)
ctx.Input.SetParam("recordUserId", userId)
}
func AfterRecordMessage(ctx *context.Context) {
record, err := object.NewRecord(ctx)
if err != nil {
fmt.Printf("AfterRecordMessage() error: %s\n", err.Error())
return
}
userId := ctx.Input.Params()["recordUserId"]
if userId != "" {
record.Organization, record.User = util.GetOwnerAndNameFromId(userId)
}
util.SafeGoroutine(func() { object.AddRecord(record) })
var record2 *casvisorsdk.Record
recordSignup := ctx.Input.Params()["recordSignup"]
if recordSignup == "true" {
record2 = object.CopyRecord(record)
record2.Action = "new-user"
var user *object.User
user, err = object.GetUser(userId)
if err != nil {
fmt.Printf("AfterRecordMessage() error: %s\n", err.Error())
return
}
if user == nil {
err = fmt.Errorf("the user: %s is not found", userId)
fmt.Printf("AfterRecordMessage() error: %s\n", err.Error())
return
}
record2.Object = util.StructToJson(user)
}
util.SafeGoroutine(func() {
object.AddRecord(record)
if record2 != nil {
object.AddRecord(record2)
}
})
}

View File

@ -255,6 +255,7 @@ func initAPI() {
beego.Router("/api/verify-captcha", &controllers.ApiController{}, "POST:VerifyCaptcha")
beego.Router("/api/reset-email-or-phone", &controllers.ApiController{}, "POST:ResetEmailOrPhone")
beego.Router("/api/get-captcha", &controllers.ApiController{}, "GET:GetCaptcha")
beego.Router("/api/get-verifications", &controllers.ApiController{}, "GET:GetVerifications")
beego.Router("/api/get-ldap-users", &controllers.ApiController{}, "GET:GetLdapUsers")
beego.Router("/api/get-ldaps", &controllers.ApiController{}, "GET:GetLdaps")
@ -300,4 +301,6 @@ func initAPI() {
beego.Router("/cas/:organization/:application/samlValidate", &controllers.RootController{}, "POST:SamlValidate")
beego.Router("/scim/*", &controllers.RootController{}, "*:HandleScim")
beego.Router("/api/faceid-signin-begin", &controllers.ApiController{}, "GET:FaceIDSigninBegin")
}

View File

@ -85,9 +85,6 @@ func GetCountryCode(prefix string, phone string) (string, error) {
if err != nil {
return "", err
}
if err != nil {
return "", err
}
countryCode := phonenumbers.GetRegionCodeForNumber(phoneNumber)
if countryCode == "" {

View File

@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@ant-design/cssinjs": "1.16.1",
"@ant-design/cssinjs": "^1.10.1",
"@ant-design/icons": "^4.7.0",
"@craco/craco": "^6.4.5",
"@crowdin/cli": "^3.7.10",

View File

@ -41,6 +41,7 @@ setTwoToneColor("rgb(87,52,211)");
class App extends Component {
constructor(props) {
super(props);
this.setThemeAlgorithm();
let storageThemeAlgorithm = [];
try {
storageThemeAlgorithm = localStorage.getItem("themeAlgorithm") ? JSON.parse(localStorage.getItem("themeAlgorithm")) : ["default"];
@ -51,6 +52,7 @@ class App extends Component {
classes: props,
selectedMenuKey: 0,
account: undefined,
accessToken: undefined,
uri: null,
themeAlgorithm: storageThemeAlgorithm,
themeData: Conf.ThemeDefault,
@ -156,6 +158,15 @@ class App extends Component {
return Setting.getLogo(themes);
}
setThemeAlgorithm() {
const currentUrl = window.location.href;
const url = new URL(currentUrl);
const themeType = url.searchParams.get("theme");
if (themeType === "dark" || themeType === "default") {
localStorage.setItem("themeAlgorithm", JSON.stringify([themeType]));
}
}
setLanguage(account) {
const language = account?.language;
if (language !== null && language !== "" && language !== i18next.language) {
@ -228,9 +239,11 @@ class App extends Component {
AuthBackend.getAccount(query)
.then((res) => {
let account = null;
let accessToken = null;
if (res.status === "ok") {
account = res.data;
account.organization = res.data2;
accessToken = res.data.accessToken;
this.setLanguage(account);
this.setTheme(Setting.getThemeData(account.organization), Conf.InitThemeAlgorithm);
@ -242,6 +255,7 @@ class App extends Component {
this.setState({
account: account,
accessToken: accessToken,
});
});
}
@ -256,6 +270,7 @@ class App extends Component {
return (
<React.Fragment>
{!this.state.account ? null : <div style={{display: "none"}} id="CasdoorApplicationName" value={this.state.account.signupApplication} />}
{!this.state.account ? null : <div style={{display: "none"}} id="CasdoorAccessToken" value={this.state.accessToken} />}
<Footer id="footer" style={
{
textAlign: "center",
@ -359,6 +374,7 @@ class App extends Component {
});
}}
onLoginSuccess={(redirectUrl) => {
window.google?.accounts?.id?.cancel();
if (redirectUrl) {
localStorage.setItem("mfaRedirectUrl", redirectUrl);
}

View File

@ -456,6 +456,10 @@ class ApplicationEditPage extends React.Component {
</Col>
<Col span={1} >
<Switch checked={this.state.application.enableSigninSession} onChange={checked => {
if (!checked) {
this.updateApplicationField("enableAutoSignin", false);
}
this.updateApplicationField("enableSigninSession", checked);
}} />
</Col>
@ -466,6 +470,11 @@ class ApplicationEditPage extends React.Component {
</Col>
<Col span={1} >
<Switch checked={this.state.application.enableAutoSignin} onChange={checked => {
if (!this.state.application.enableSigninSession && checked) {
Setting.showMessage("error", i18next.t("application:Please enable \"Signin session\" first before enabling \"Auto signin\""));
return;
}
this.updateApplicationField("enableAutoSignin", checked);
}} />
</Col>

View File

@ -177,6 +177,16 @@ class GroupEditPage extends React.Component {
)} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Users"), i18next.t("general:Users - Tooltip"))} :
</Col>
<Col style={{marginTop: "5px"}} span={22} >
{
Setting.getTags(this.state.group.users, "users")
}
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
{Setting.getLabel(i18next.t("general:Is enabled"), i18next.t("general:Is enabled - Tooltip"))} :

View File

@ -195,6 +195,17 @@ class GroupListPage extends BaseListPage {
</Link>;
},
},
{
title: i18next.t("general:Users"),
dataIndex: "users",
key: "users",
// width: "200px",
sorter: true,
...this.getColumnSearchProps("users"),
render: (text, record, index) => {
return Setting.getTags(text, "users");
},
},
{
title: i18next.t("general:Action"),
dataIndex: "",

View File

@ -34,8 +34,8 @@ import OrganizationListPage from "./OrganizationListPage";
import OrganizationEditPage from "./OrganizationEditPage";
import UserListPage from "./UserListPage";
import GroupTreePage from "./GroupTreePage";
import GroupListPage from "./GroupList";
import GroupEditPage from "./GroupEdit";
import GroupListPage from "./GroupListPage";
import GroupEditPage from "./GroupEditPage";
import UserEditPage from "./UserEditPage";
import InvitationListPage from "./InvitationListPage";
import InvitationEditPage from "./InvitationEditPage";
@ -92,6 +92,7 @@ import * as AuthBackend from "./auth/AuthBackend";
import {clearWeb3AuthToken} from "./auth/Web3Auth";
import TransactionListPage from "./TransactionListPage";
import TransactionEditPage from "./TransactionEditPage";
import VerificationListPage from "./VerificationListPage";
function ManagementPage(props) {
@ -293,6 +294,7 @@ function ManagementPage(props) {
Conf.CasvisorUrl ? Setting.getItem(<a target="_blank" rel="noreferrer" href={Conf.CasvisorUrl}>{i18next.t("general:Records")}</a>, "/records")
: Setting.getItem(<Link to="/records">{i18next.t("general:Records")}</Link>, "/records"),
Setting.getItem(<Link to="/tokens">{i18next.t("general:Tokens")}</Link>, "/tokens"),
Setting.getItem(<Link to="/verifications">{i18next.t("general:Verifications")}</Link>, "/verifications"),
]));
res.push(Setting.getItem(<Link style={{color: textColor}} to="/products">{i18next.t("general:Business & Payments")}</Link>, "/business", <DollarTwoTone twoToneColor={twoToneColor} />, [
@ -360,6 +362,7 @@ function ManagementPage(props) {
<Route exact path="/resources" render={(props) => renderLoginIfNotLoggedIn(<ResourceListPage account={account} {...props} />)} />
<Route exact path="/certs" render={(props) => renderLoginIfNotLoggedIn(<CertListPage account={account} {...props} />)} />
<Route exact path="/certs/:organizationName/:certName" render={(props) => renderLoginIfNotLoggedIn(<CertEditPage account={account} {...props} />)} />
<Route exact path="/verifications" render={(props) => renderLoginIfNotLoggedIn(<VerificationListPage account={account} {...props} />)} />
<Route exact path="/roles" render={(props) => renderLoginIfNotLoggedIn(<RoleListPage account={account} {...props} />)} />
<Route exact path="/roles/:organizationName/:roleName" render={(props) => renderLoginIfNotLoggedIn(<RoleEditPage account={account} {...props} />)} />
<Route exact path="/permissions" render={(props) => renderLoginIfNotLoggedIn(<PermissionListPage account={account} {...props} />)} />

View File

@ -40,6 +40,14 @@ require("codemirror/mode/css/css");
const {Option} = Select;
const {TextArea} = Input;
const defaultUserMapping = {
id: "id",
username: "username",
displayName: "displayName",
email: "email",
avatarUrl: "avatarUrl",
};
class ProviderEditPage extends React.Component {
constructor(props) {
super(props);
@ -70,7 +78,7 @@ class ProviderEditPage extends React.Component {
if (res.status === "ok") {
const provider = res.data;
provider.userMapping = provider.userMapping || {};
provider.userMapping = provider.userMapping || defaultUserMapping;
this.setState({
provider: provider,
});
@ -141,8 +149,16 @@ class ProviderEditPage extends React.Component {
}
updateUserMappingField(key, value) {
const requiredKeys = ["id", "username", "displayName"];
const provider = this.state.provider;
if (value === "" && requiredKeys.includes(key)) {
Setting.showMessage("error", i18next.t("provider:This field is required"));
return;
}
provider.userMapping[key] = value;
this.setState({
provider: provider,
});
@ -228,7 +244,7 @@ class ProviderEditPage extends React.Component {
return Setting.getLabel(i18next.t("provider:Client secret"), i18next.t("provider:Client secret - Tooltip"));
}
case "Email":
if (provider.type === "Azure ACS") {
if (provider.type === "Azure ACS" || provider.type === "SendGrid") {
return Setting.getLabel(i18next.t("provider:Secret key"), i18next.t("provider:Secret key - Tooltip"));
} else {
return Setting.getLabel(i18next.t("general:Password"), i18next.t("general:Password - Tooltip"));
@ -713,7 +729,7 @@ class ProviderEditPage extends React.Component {
<React.Fragment>
{
(this.state.provider.category === "Storage" && this.state.provider.type === "Google Cloud Storage") ||
(this.state.provider.category === "Email" && this.state.provider.type === "Azure ACS") ||
(this.state.provider.category === "Email" && (this.state.provider.type === "Azure ACS" || this.state.provider.type === "SendGrid")) ||
(this.state.provider.category === "Notification" && (this.state.provider.type === "Line" || this.state.provider.type === "Telegram" || this.state.provider.type === "Bark" || this.state.provider.type === "Discord" || this.state.provider.type === "Slack" || this.state.provider.type === "Pushbullet" || this.state.provider.type === "Pushover" || this.state.provider.type === "Lark" || this.state.provider.type === "Microsoft Teams")) ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
@ -754,7 +770,7 @@ class ProviderEditPage extends React.Component {
</Col>
</Row>
{
(this.state.provider.type === "WeChat Pay") || (this.state.provider.category === "Email" && this.state.provider.type === "Azure ACS") ? null : (
(this.state.provider.type === "WeChat Pay") || (this.state.provider.category === "Email" && (this.state.provider.type === "Azure ACS" || this.state.provider.type === "SendGrid")) ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{this.getClientSecret2Label(this.state.provider)} :
@ -969,17 +985,19 @@ class ProviderEditPage extends React.Component {
</React.Fragment>
) : this.state.provider.category === "Email" ? (
<React.Fragment>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:Host"), i18next.t("provider:Host - Tooltip"))} :
</Col>
<Col span={22} >
<Input prefix={<LinkOutlined />} value={this.state.provider.host} onChange={e => {
this.updateProviderField("host", e.target.value);
}} />
</Col>
</Row>
{["Azure ACS"].includes(this.state.provider.type) ? null : (
{["SendGrid"].includes(this.state.provider.type) ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:Host"), i18next.t("provider:Host - Tooltip"))} :
</Col>
<Col span={22} >
<Input prefix={<LinkOutlined />} value={this.state.provider.host} onChange={e => {
this.updateProviderField("host", e.target.value);
}} />
</Col>
</Row>
)}
{["Azure ACS", "SendGrid"].includes(this.state.provider.type) ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:Port"), i18next.t("provider:Port - Tooltip"))} :
@ -991,7 +1009,7 @@ class ProviderEditPage extends React.Component {
</Col>
</Row>
)}
{["Azure ACS"].includes(this.state.provider.type) ? null : (
{["Azure ACS", "SendGrid"].includes(this.state.provider.type) ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:Disable SSL"), i18next.t("provider:Disable SSL - Tooltip"))} :
@ -1057,7 +1075,7 @@ class ProviderEditPage extends React.Component {
this.updateProviderField("receiver", e.target.value);
}} />
</Col>
{["Azure ACS"].includes(this.state.provider.type) ? null : (
{["Azure ACS", "SendGrid"].includes(this.state.provider.type) ? null : (
<Button style={{marginLeft: "10px", marginBottom: "5px"}} onClick={() => ProviderEditTestEmail.connectSmtpServer(this.state.provider)} >
{i18next.t("provider:Test SMTP Connection")}
</Button>

View File

@ -151,6 +151,14 @@ class RecordListPage extends BaseListPage {
sorter: true,
...this.getColumnSearchProps("language"),
},
{
title: i18next.t("record:Response"),
dataIndex: "response",
key: "response",
width: "90px",
sorter: true,
...this.getColumnSearchProps("response"),
},
{
title: i18next.t("record:Object"),
dataIndex: "object",
@ -179,7 +187,7 @@ class RecordListPage extends BaseListPage {
sorter: true,
fixed: (Setting.isMobile()) ? "false" : "right",
render: (text, record, index) => {
if (!["signup", "login", "logout", "update-user"].includes(record.action)) {
if (!["signup", "login", "logout", "update-user", "new-user"].includes(record.action)) {
return null;
}

View File

@ -181,6 +181,10 @@ export const OtherProviderInfo = {
logo: `${StaticBaseUrl}/img/social_azure.png`,
url: "https://learn.microsoft.com/zh-cn/azure/communication-services",
},
"SendGrid": {
logo: `${StaticBaseUrl}/img/email_sendgrid.png`,
url: "https://sendgrid.com/",
},
"Custom HTTP Email": {
logo: `${StaticBaseUrl}/img/social_default.png`,
url: "https://casdoor.org/docs/provider/email/overview",
@ -1015,6 +1019,7 @@ export function getProviderTypeOptions(category) {
{id: "SUBMAIL", name: "SUBMAIL"},
{id: "Mailtrap", name: "Mailtrap"},
{id: "Azure ACS", name: "Azure ACS"},
{id: "SendGrid", name: "SendGrid"},
{id: "Custom HTTP Email", name: "Custom HTTP Email"},
]
);

View File

@ -13,7 +13,7 @@
// limitations under the License.
import React from "react";
import {Button, Card, Col, Form, Input, InputNumber, List, Result, Row, Select, Space, Spin, Switch, Tag} from "antd";
import {Button, Card, Col, Form, Input, InputNumber, List, Result, Row, Select, Space, Spin, Switch, Tag, Tooltip} from "antd";
import {withRouter} from "react-router-dom";
import {TotpMfaType} from "./auth/MfaSetupPage";
import * as GroupBackend from "./backend/GroupBackend";
@ -407,7 +407,17 @@ class UserEditPage extends React.Component {
{Setting.getLabel(i18next.t("general:Password"), i18next.t("general:Password - Tooltip"))} :
</Col>
<Col span={22} >
<PasswordModal user={this.state.user} userName={this.state.userName} organization={this.getUserOrganization()} account={this.props.account} disabled={disabled} />
{
(this.state.user.name === this.state.userName) ? (
<PasswordModal user={this.state.user} userName={this.state.userName} organization={this.getUserOrganization()} account={this.props.account} disabled={disabled} />
) : (
<Tooltip placement={"topLeft"} title={i18next.t("user:You have changed the username, please save your change first before modifying the password")}>
<span>
<PasswordModal user={this.state.user} userName={this.state.userName} organization={this.getUserOrganization()} account={this.props.account} disabled={true} />
</span>
</Tooltip>
)
}
</Col>
</Row>
);

View File

@ -0,0 +1,189 @@
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import BaseListPage from "./BaseListPage";
import * as Setting from "./Setting";
import moment from "moment/moment";
import * as VerificationBackend from "./backend/VerificationBackend";
import i18next from "i18next";
import {Link} from "react-router-dom";
import React from "react";
import {Table} from "antd";
class VerificationListPage extends BaseListPage {
newVerification() {
const randomName = Setting.getRandomName();
return {
owner: "admin",
name: `Verification_${randomName}`,
createdTime: moment().format(),
};
}
renderTable(verifications) {
const columns = [
{
title: i18next.t("general:Organization"),
dataIndex: "owner",
key: "owner",
width: "120px",
sorter: true,
...this.getColumnSearchProps("owner"),
render: (text, record, index) => {
if (text === "admin") {
return `(${i18next.t("general:empty")})`;
}
return (
<Link to={`/organizations/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Name"),
dataIndex: "name",
key: "name",
width: "260px",
fixed: "left",
sorter: true,
...this.getColumnSearchProps("name"),
},
{
title: i18next.t("general:Created time"),
dataIndex: "createdTime",
key: "createdTime",
width: "160px",
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
},
},
{
title: i18next.t("provider:Type"),
dataIndex: "type",
key: "type",
width: "90px",
sorter: true,
...this.getColumnSearchProps("type"),
},
{
title: i18next.t("general:User"),
dataIndex: "user",
key: "user",
width: "120px",
sorter: true,
...this.getColumnSearchProps("user"),
render: (text, record, index) => {
return (
<Link to={`/users/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Provider"),
dataIndex: "provider",
key: "provider",
width: "150px",
sorter: true,
...this.getColumnSearchProps("provider"),
render: (text, record, index) => {
return (
<Link to={`/providers/${record.owner}/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("verification:Receiver"),
dataIndex: "receiver",
key: "receiver",
width: "120px",
sorter: true,
...this.getColumnSearchProps("receiver"),
},
{
title: i18next.t("login:Verification code"),
dataIndex: "code",
key: "code",
width: "150px",
sorter: true,
...this.getColumnSearchProps("code"),
},
];
const paginationProps = {
total: this.state.pagination.total,
showQuickJumper: true,
showSizeChanger: true,
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
};
return (
<div>
<Table scroll={{x: "max-content"}} columns={columns} dataSource={verifications} rowKey={(record) => `${record.owner}/${record.name}`} size="middle" bordered pagination={paginationProps}
title={() => (
<div>
{i18next.t("general:Verifications")}&nbsp;&nbsp;&nbsp;&nbsp;
</div>
)}
loading={this.state.loading}
onChange={this.handleTableChange}
/>
</div>
);
}
fetch = (params = {}) => {
let field = params.searchedColumn, value = params.searchText;
const sortField = params.sortField, sortOrder = params.sortOrder;
if (params.type !== undefined && params.type !== null) {
field = "type";
value = params.type;
}
this.setState({loading: true});
VerificationBackend.getVerifications("", Setting.isDefaultOrganizationSelected(this.props.account) ? "" : Setting.getRequestOrganization(this.props.account), params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
.then((res) => {
this.setState({
loading: false,
});
if (res.status === "ok") {
this.setState({
data: res.data,
pagination: {
...params.pagination,
total: res.data2,
},
searchText: params.searchText,
searchedColumn: params.searchedColumn,
});
} else {
if (Setting.isResponseDenied(res)) {
this.setState({
isAuthorized: false,
});
} else {
Setting.showMessage("error", res.msg);
}
}
});
};
}
export default VerificationListPage;

View File

@ -275,7 +275,7 @@ class WebhookEditPage extends React.Component {
}} >
{
(
["signup", "login", "logout"].concat(this.getApiPaths()).map((option, index) => {
["signup", "login", "logout", "new-user"].concat(this.getApiPaths()).map((option, index) => {
return (
<Option key={option} value={option}>{option}</Option>
);

View File

@ -21,7 +21,7 @@ import * as Setting from "../Setting";
import i18next from "i18next";
import {SendCodeInput} from "../common/SendCodeInput";
import * as UserBackend from "../backend/UserBackend";
import {CheckCircleOutlined, KeyOutlined, LockOutlined, SolutionOutlined, UserOutlined} from "@ant-design/icons";
import {ArrowLeftOutlined, CheckCircleOutlined, KeyOutlined, LockOutlined, SolutionOutlined, UserOutlined} from "@ant-design/icons";
import CustomGithubCorner from "../common/CustomGithubCorner";
import {withRouter} from "react-router-dom";
import * as PasswordChecker from "../common/PasswordChecker";
@ -443,6 +443,18 @@ class ForgetPage extends React.Component {
);
}
stepBack() {
if (this.state.current > 0) {
this.setState({
current: this.state.current - 1,
});
} else if (this.props.history.length > 1) {
this.props.history.goBack();
} else {
Setting.redirectToLoginPage(this.getApplicationObj(), this.props.history);
}
}
render() {
const application = this.getApplicationObj();
if (application === undefined) {
@ -456,6 +468,9 @@ class ForgetPage extends React.Component {
<React.Fragment>
<CustomGithubCorner />
<div className="forget-content" style={{padding: Setting.isMobile() ? "0" : null, boxShadow: Setting.isMobile() ? "none" : null}}>
<Button type="text" style={{position: "relative", left: Setting.isMobile() ? "10px" : "-90px", top: 0}} size={"large"} onClick={() => {this.stepBack();}}>
<ArrowLeftOutlined style={{fontSize: "24px"}} />
</Button>
<Row>
<Col span={24} style={{justifyContent: "center"}}>
<Row>

View File

@ -52,7 +52,7 @@ export function GoogleOneTapLoginVirtualButton(prop) {
redirectUri = `${redirectUri}?state=${state}&code=${encodeURIComponent(code)}`;
Setting.goToLink(redirectUri);
},
disableCancelOnUnmount: true,
disableCancelOnUnmount: false,
});
}

View File

@ -346,10 +346,28 @@ class LoginPage extends React.Component {
return;
}
if (this.state.loginMethod === "faceId") {
this.setState({
openFaceRecognitionModal: true,
values: values,
});
let username = this.state.username;
if (username === null || username === "") {
username = values["username"];
}
const application = this.getApplicationObj();
fetch(`${Setting.ServerUrl}/api/faceid-signin-begin?owner=${application.organization}&name=${username}`, {
method: "GET",
credentials: "include",
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json())
.then((res) => {
if (res.status === "error") {
Setting.showMessage("error", res.msg);
return;
}
this.setState({
openFaceRecognitionModal: true,
values: values,
});
});
return;
}
if (this.state.loginMethod === "password" || this.state.loginMethod === "ldap") {
@ -666,7 +684,8 @@ class LoginPage extends React.Component {
>
{
this.state.loginMethod === "webAuthn" ? i18next.t("login:Sign in with WebAuthn") :
i18next.t("login:Sign In")
this.state.loginMethod === "faceId" ? i18next.t("login:Sign in with Face ID") :
i18next.t("login:Sign In")
}
</Button>
{
@ -1154,7 +1173,7 @@ class LoginPage extends React.Component {
};
return (
<div style={{height: 300}}>
<div style={{height: 300, minWidth: 320}}>
{renderChoiceBox()}
</div>
);

View File

@ -13,7 +13,7 @@
// limitations under the License.
import React from "react";
import {Button, Form, Input, Result} from "antd";
import {Button, Form, Input, Radio, Result, Row} from "antd";
import * as Setting from "../Setting";
import * as AuthBackend from "./AuthBackend";
import * as ProviderButton from "./ProviderButton";
@ -71,6 +71,7 @@ class SignupPage extends React.Component {
applicationName: (props.applicationName ?? props.match?.params?.applicationName) ?? null,
email: "",
phone: "",
emailOrPhoneMode: "",
countryCode: "",
emailCode: "",
phoneCode: "",
@ -360,130 +361,176 @@ class SignupPage extends React.Component {
<RegionSelect onChange={(value) => {this.setState({region: value});}} />
</Form.Item>
);
} else if (signupItem.name === "Email") {
return (
<React.Fragment>
<Form.Item
name="email"
label={signupItem.label ? signupItem.label : i18next.t("general:Email")}
rules={[
{
required: required,
message: i18next.t("signup:Please input your Email!"),
},
{
validator: (_, value) => {
if (this.state.email !== "" && !Setting.isValidEmail(this.state.email)) {
this.setState({validEmail: false});
return Promise.reject(i18next.t("signup:The input is not valid Email!"));
}
this.setState({validEmail: true});
return Promise.resolve();
},
},
]}
>
<Input placeholder={signupItem.placeholder} disabled={this.state.invitation !== undefined && this.state.invitation.email !== ""} onChange={e => this.setState({email: e.target.value})} />
</Form.Item>
{
signupItem.rule !== "No verification" &&
} else if (signupItem.name === "Email" || signupItem.name === "Phone" || signupItem.name === "Email or Phone" || signupItem.name === "Phone or Email") {
const renderEmailItem = () => {
return (
<React.Fragment>
<Form.Item
name="emailCode"
label={signupItem.label ? signupItem.label : i18next.t("code:Email code")}
rules={[{
required: required,
message: i18next.t("code:Please input your verification code!"),
}]}
>
<SendCodeInput
disabled={!this.state.validEmail}
method={"signup"}
onButtonClickArgs={[this.state.email, "email", Setting.getApplicationName(application)]}
application={application}
/>
</Form.Item>
}
</React.Fragment>
);
} else if (signupItem.name === "Phone") {
return (
<React.Fragment>
<Form.Item label={signupItem.label ? signupItem.label : i18next.t("general:Phone")} required={required}>
<Input.Group compact>
<Form.Item
name="countryCode"
noStyle
rules={[
{
required: required,
message: i18next.t("signup:Please select your country code!"),
},
]}
>
<CountryCodeSelect
style={{width: "35%"}}
countryCodes={this.getApplicationObj().organizationObj.countryCodes}
/>
</Form.Item>
<Form.Item
name="phone"
dependencies={["countryCode"]}
noStyle
rules={[
{
required: required,
message: i18next.t("signup:Please input your phone number!"),
},
({getFieldValue}) => ({
validator: (_, value) => {
if (!required && !value) {
return Promise.resolve();
}
if (value && !Setting.isValidPhone(value, getFieldValue("countryCode"))) {
this.setState({validPhone: false});
return Promise.reject(i18next.t("signup:The input is not valid Phone!"));
}
this.setState({validPhone: true});
return Promise.resolve();
},
}),
]}
>
<Input
placeholder={signupItem.placeholder}
style={{width: "65%"}}
disabled={this.state.invitation !== undefined && this.state.invitation.phone !== ""}
onChange={e => this.setState({phone: e.target.value})}
/>
</Form.Item>
</Input.Group>
</Form.Item>
{
signupItem.rule !== "No verification" &&
<Form.Item
name="phoneCode"
label={signupItem.label ? signupItem.label : i18next.t("code:Phone code")}
name="email"
label={signupItem.label ? signupItem.label : i18next.t("general:Email")}
rules={[
{
required: required,
message: i18next.t("code:Please input your phone verification code!"),
message: i18next.t("signup:Please input your Email!"),
},
{
validator: (_, value) => {
if (this.state.email !== "" && !Setting.isValidEmail(this.state.email)) {
this.setState({validEmail: false});
return Promise.reject(i18next.t("signup:The input is not valid Email!"));
}
this.setState({validEmail: true});
return Promise.resolve();
},
},
]}
>
<SendCodeInput
disabled={!this.state.validPhone}
method={"signup"}
onButtonClickArgs={[this.state.phone, "phone", Setting.getApplicationName(application)]}
application={application}
countryCode={this.form.current?.getFieldValue("countryCode")}
/>
<Input placeholder={signupItem.placeholder} disabled={this.state.invitation !== undefined && this.state.invitation.email !== ""} onChange={e => this.setState({email: e.target.value})} />
</Form.Item>
}
</React.Fragment>
);
{
signupItem.rule !== "No verification" &&
<Form.Item
name="emailCode"
label={signupItem.label ? signupItem.label : i18next.t("code:Email code")}
rules={[{
required: required,
message: i18next.t("code:Please input your verification code!"),
}]}
>
<SendCodeInput
disabled={!this.state.validEmail}
method={"signup"}
onButtonClickArgs={[this.state.email, "email", Setting.getApplicationName(application)]}
application={application}
/>
</Form.Item>
}
</React.Fragment>
);
};
const renderPhoneItem = () => {
return (
<React.Fragment>
<Form.Item label={signupItem.label ? signupItem.label : i18next.t("general:Phone")} required={required}>
<Input.Group compact>
<Form.Item
name="countryCode"
noStyle
rules={[
{
required: required,
message: i18next.t("signup:Please select your country code!"),
},
]}
>
<CountryCodeSelect
style={{width: "35%"}}
countryCodes={this.getApplicationObj().organizationObj.countryCodes}
/>
</Form.Item>
<Form.Item
name="phone"
dependencies={["countryCode"]}
noStyle
rules={[
{
required: required,
message: i18next.t("signup:Please input your phone number!"),
},
({getFieldValue}) => ({
validator: (_, value) => {
if (!required && !value) {
return Promise.resolve();
}
if (value && !Setting.isValidPhone(value, getFieldValue("countryCode"))) {
this.setState({validPhone: false});
return Promise.reject(i18next.t("signup:The input is not valid Phone!"));
}
this.setState({validPhone: true});
return Promise.resolve();
},
}),
]}
>
<Input
placeholder={signupItem.placeholder}
style={{width: "65%"}}
disabled={this.state.invitation !== undefined && this.state.invitation.phone !== ""}
onChange={e => this.setState({phone: e.target.value})}
/>
</Form.Item>
</Input.Group>
</Form.Item>
{
signupItem.rule !== "No verification" &&
<Form.Item
name="phoneCode"
label={signupItem.label ? signupItem.label : i18next.t("code:Phone code")}
rules={[
{
required: required,
message: i18next.t("code:Please input your phone verification code!"),
},
]}
>
<SendCodeInput
disabled={!this.state.validPhone}
method={"signup"}
onButtonClickArgs={[this.state.phone, "phone", Setting.getApplicationName(application)]}
application={application}
countryCode={this.form.current?.getFieldValue("countryCode")}
/>
</Form.Item>
}
</React.Fragment>
);
};
if (signupItem.name === "Email") {
return renderEmailItem();
} else if (signupItem.name === "Phone") {
return renderPhoneItem();
} else if (signupItem.name === "Email or Phone" || signupItem.name === "Phone or Email") {
let emailOrPhoneMode = this.state.emailOrPhoneMode;
if (emailOrPhoneMode === "") {
emailOrPhoneMode = signupItem.name === "Email or Phone" ? "Email" : "Phone";
}
return (
<React.Fragment>
<Row style={{marginTop: "30px", marginBottom: "20px"}} >
<Radio.Group style={{width: "400px"}} buttonStyle="solid" onChange={e => {
this.setState({
emailOrPhoneMode: e.target.value,
});
}} value={emailOrPhoneMode}>
{
signupItem.name === "Email or Phone" ? (
<React.Fragment>
<Radio.Button value={"Email"}>{i18next.t("general:Email")}</Radio.Button>
<Radio.Button value={"Phone"}>{i18next.t("general:Phone")}</Radio.Button>
</React.Fragment>
) : (
<React.Fragment>
<Radio.Button value={"Phone"}>{i18next.t("general:Phone")}</Radio.Button>
<Radio.Button value={"Email"}>{i18next.t("general:Email")}</Radio.Button>
</React.Fragment>
)
}
</Radio.Group>
</Row>
{
emailOrPhoneMode === "Email" ? renderEmailItem() : renderPhoneItem()
}
</React.Fragment>
);
} else {
return null;
}
} else if (signupItem.name === "Password") {
return (
<Form.Item

View File

@ -0,0 +1,35 @@
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import * as Setting from "../Setting";
export function getVerifications(owner, organization, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-verifications?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include",
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}
export function getVerification(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-verification?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include",
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
"Users": "Users",
"Users under all organizations": "Users under all organizations",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "empty",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Redirecting, please wait.",
"Sign In": "Sign In",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Sign in with {type}",
"Signing in...": "Signing in...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Email address to receive test mails",
"Test SMTP Connection": "Test SMTP Connection",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL",
"Type": "Type",
@ -888,7 +891,9 @@
"admin (Shared)": "admin (Shared)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Copy Link",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthn credentials",
"input password": "input password"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Content type",
"Content type - Tooltip": "Content type",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Tags, denen der Benutzer angehört, standardmäßig auf \"normaler Benutzer\" festgelegt",
"Users": "Benutzer",
"Users under all organizations": "Benutzer unter allen Organisationen",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "leere",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Umleitung, bitte warten.",
"Sign In": "Anmelden",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Melden Sie sich mit WebAuthn an",
"Sign in with {type}": "Melden Sie sich mit {type} an",
"Signing in...": "Anmelden...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "E-Mail-Adresse zum Empfangen von Test-E-Mails",
"Test SMTP Connection": "Testen Sie die SMTP-Verbindung",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Token-URL",
"Token URL - Tooltip": "Token-URL",
"Type": "Typ",
@ -888,7 +891,9 @@
"admin (Shared)": "admin (Gemeinsam)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Kopiere den Link",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthn-Anmeldeinformationen",
"input password": "Eingabe des Passworts"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Content-Type",
"Content type - Tooltip": "Inhaltstyp",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
"Users": "Users",
"Users under all organizations": "Users under all organizations",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "empty",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Redirecting, please wait.",
"Sign In": "Sign In",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Sign in with {type}",
"Signing in...": "Signing in...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Email address to receive test mails",
"Test SMTP Connection": "Test SMTP Connection",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL",
"Type": "Type",
@ -888,7 +891,9 @@
"admin (Shared)": "admin (Shared)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Copy Link",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthn credentials",
"input password": "input password"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Content type",
"Content type - Tooltip": "Content type",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Etiquetas a las que el usuario pertenece, con una configuración predeterminada en \"usuario-normal\"",
"Users": "Usuarios",
"Users under all organizations": "Usuarios bajo todas las organizaciones",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "vacío",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Redirigiendo, por favor espera.",
"Sign In": "Iniciar sesión",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Iniciar sesión con WebAuthn",
"Sign in with {type}": "Inicia sesión con {tipo}",
"Signing in...": "Iniciando sesión...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Dirección de correo electrónico para recibir mensajes de prueba",
"Test SMTP Connection": "Prueba de conexión SMTP",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Token URL",
"Token URL - Tooltip": "URL de token",
"Type": "Tipo",
@ -888,7 +891,9 @@
"admin (Shared)": "administrador (compartido)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Copiar enlace",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "Credenciales de WebAuthn",
"input password": "Ingresar contraseña"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Tipo de contenido",
"Content type - Tooltip": "Tipo de contenido",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
"Users": "Users",
"Users under all organizations": "Users under all organizations",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "empty",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Redirecting, please wait.",
"Sign In": "Sign In",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Sign in with {type}",
"Signing in...": "Signing in...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Email address to receive test mails",
"Test SMTP Connection": "Test SMTP Connection",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL",
"Type": "Type",
@ -888,7 +891,9 @@
"admin (Shared)": "admin (Shared)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Copy Link",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthn credentials",
"input password": "input password"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Content type",
"Content type - Tooltip": "Content type",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
"Users": "Users",
"Users under all organizations": "Users under all organizations",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "empty",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Redirecting, please wait.",
"Sign In": "Sign In",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Sign in with {type}",
"Signing in...": "Signing in...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Email address to receive test mails",
"Test SMTP Connection": "Test SMTP Connection",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL",
"Type": "Type",
@ -888,7 +891,9 @@
"admin (Shared)": "admin (Shared)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Copy Link",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthn credentials",
"input password": "input password"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Content type",
"Content type - Tooltip": "Content type",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Étiquettes associées au compte, avec une valeur par défaut \"normal-user\"",
"Users": "Comptes",
"Users under all organizations": "Comptes sous toutes les organisations",
"Verifications": "Verifications",
"Webhooks": "Crochets web",
"You can only select one physical group": "Vous ne pouvez sélectionner qu'un seul groupe physique",
"empty": "vide",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Veuillez entrer une organisation pour vous connecter",
"Redirecting, please wait.": "Redirection en cours, veuillez patienter.",
"Sign In": "Se connecter",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Connectez-vous avec WebAuthn",
"Sign in with {type}": "Connectez-vous avec {type}",
"Signing in...": "Connexion en cours...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Adresse e-mail pour recevoir des courriels de test",
"Test SMTP Connection": "Test de connexion SMTP",
"Third-party": "Tierce partie",
"This field is required": "This field is required",
"Token URL": "URL de jeton",
"Token URL - Tooltip": "URL de jeton",
"Type": "Type de texte",
@ -888,7 +891,9 @@
"admin (Shared)": "admin (Partagé)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Copier le lien",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "Identifiants WebAuthn",
"input password": "saisir le mot de passe"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Type de contenu",
"Content type - Tooltip": "Type de contenu",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
"Users": "Users",
"Users under all organizations": "Users under all organizations",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "empty",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Redirecting, please wait.",
"Sign In": "Sign In",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Sign in with {type}",
"Signing in...": "Signing in...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Email address to receive test mails",
"Test SMTP Connection": "Test SMTP Connection",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL",
"Type": "Type",
@ -888,7 +891,9 @@
"admin (Shared)": "admin (Shared)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Copy Link",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthn credentials",
"input password": "input password"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Content type",
"Content type - Tooltip": "Content type",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Tag yang dimiliki oleh pengguna, defaultnya adalah \"normal-user\"",
"Users": "Pengguna-pengguna",
"Users under all organizations": "Pengguna di bawah semua organisasi",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "kosong",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Mengalihkan, harap tunggu.",
"Sign In": "Masuk",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Masuk dengan WebAuthn",
"Sign in with {type}": "Masuk dengan {type}",
"Signing in...": "Masuk...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Alamat email untuk menerima email percobaan",
"Test SMTP Connection": "Tes Koneksi SMTP",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Token URL: Tautan Token",
"Token URL - Tooltip": "Token URL: URL Token",
"Type": "Jenis",
@ -888,7 +891,9 @@
"admin (Shared)": "Admin (Berbagi)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Salin Tautan",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "Kredensial WebAuthn",
"input password": "masukkan kata sandi"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Jenis konten",
"Content type - Tooltip": "Tipe konten",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
"Users": "Users",
"Users under all organizations": "Users under all organizations",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "empty",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Redirecting, please wait.",
"Sign In": "Sign In",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Sign in with {type}",
"Signing in...": "Signing in...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Email address to receive test mails",
"Test SMTP Connection": "Test SMTP Connection",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL",
"Type": "Type",
@ -888,7 +891,9 @@
"admin (Shared)": "admin (Shared)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Copy Link",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthn credentials",
"input password": "input password"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Content type",
"Content type - Tooltip": "Content type",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "ユーザーが属するタグは、デフォルトでは「通常ユーザー」となります",
"Users": "ユーザー",
"Users under all organizations": "すべての組織のユーザー",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "空",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "リダイレクト中、お待ちください。",
"Sign In": "サインイン",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "WebAuthnでサインインしてください",
"Sign in with {type}": "{type}でサインインしてください",
"Signing in...": "サインイン中...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "テストメールを受け取るためのメールアドレス",
"Test SMTP Connection": "SMTP接続をテストする",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "トークンのURL",
"Token URL - Tooltip": "トークンURL",
"Type": "タイプ",
@ -888,7 +891,9 @@
"admin (Shared)": "管理者(共有)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "コピー リンク",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthnの資格情報",
"input password": "パスワードを入力してください"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "コンテンツタイプ",
"Content type - Tooltip": "コンテンツタイプ",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
"Users": "Users",
"Users under all organizations": "Users under all organizations",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "empty",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Redirecting, please wait.",
"Sign In": "Sign In",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Sign in with {type}",
"Signing in...": "Signing in...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Email address to receive test mails",
"Test SMTP Connection": "Test SMTP Connection",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL",
"Type": "Type",
@ -888,7 +891,9 @@
"admin (Shared)": "admin (Shared)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Copy Link",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthn credentials",
"input password": "input password"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Content type",
"Content type - Tooltip": "Content type",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "사용자가 속한 태그는 기본적으로 \"보통 사용자\"로 설정됩니다",
"Users": "사용자",
"Users under all organizations": "모든 조직의 사용자",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "빈",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "리디렉팅 중입니다. 잠시 기다려주세요.",
"Sign In": "로그인",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "WebAuthn으로 로그인하세요",
"Sign in with {type}": "{type}로 로그인하세요",
"Signing in...": "로그인 중...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "테스트 메일을 받을 이메일 주소",
"Test SMTP Connection": "테스트 SMTP 연결",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "토큰 URL",
"Token URL - Tooltip": "토큰 URL",
"Type": "타입",
@ -888,7 +891,9 @@
"admin (Shared)": "관리자 (공유)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "링크 복사하기",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "웹 인증 자격증명",
"input password": "비밀번호를 입력해주세요"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "콘텐츠 유형",
"Content type - Tooltip": "콘텐츠 유형",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
"Users": "Users",
"Users under all organizations": "Users under all organizations",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "empty",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Redirecting, please wait.",
"Sign In": "Sign In",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Sign in with {type}",
"Signing in...": "Signing in...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Email address to receive test mails",
"Test SMTP Connection": "Test SMTP Connection",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL",
"Type": "Type",
@ -888,7 +891,9 @@
"admin (Shared)": "admin (Shared)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Copy Link",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthn credentials",
"input password": "input password"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Content type",
"Content type - Tooltip": "Content type",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
"Users": "Users",
"Users under all organizations": "Users under all organizations",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "empty",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Redirecting, please wait.",
"Sign In": "Sign In",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Sign in with {type}",
"Signing in...": "Signing in...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Email address to receive test mails",
"Test SMTP Connection": "Test SMTP Connection",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL",
"Type": "Type",
@ -888,7 +891,9 @@
"admin (Shared)": "admin (Shared)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Copy Link",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthn credentials",
"input password": "input password"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Content type",
"Content type - Tooltip": "Content type",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
"Users": "Users",
"Users under all organizations": "Users under all organizations",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "empty",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Redirecting, please wait.",
"Sign In": "Sign In",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Sign in with {type}",
"Signing in...": "Signing in...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Email address to receive test mails",
"Test SMTP Connection": "Test SMTP Connection",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL",
"Type": "Type",
@ -888,7 +891,9 @@
"admin (Shared)": "admin (Shared)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Copy Link",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthn credentials",
"input password": "input password"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Content type",
"Content type - Tooltip": "Content type",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Tags às quais o usuário pertence, com valor padrão de \"usuário-normal\"",
"Users": "Usuários",
"Users under all organizations": "Usuários em todas as organizações",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "vazio",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Redirecionando, por favor aguarde.",
"Sign In": "Entrar",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Entrar com WebAuthn",
"Sign in with {type}": "Entrar com {type}",
"Signing in...": "Entrando...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Endereço de e-mail para receber e-mails de teste",
"Test SMTP Connection": "Testar Conexão SMTP",
"Third-party": "Terceiros",
"This field is required": "This field is required",
"Token URL": "URL do Token",
"Token URL - Tooltip": "URL do Token",
"Type": "Tipo",
@ -888,7 +891,9 @@
"admin (Shared)": "admin (Compartilhado)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Copiar Link",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "Credenciais WebAuthn",
"input password": "Digite a senha"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Tipo de conteúdo",
"Content type - Tooltip": "Tipo de conteúdo",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Теги, к которым принадлежит пользователь, по умолчанию \"обычный пользователь\"",
"Users": "Пользователи",
"Users under all organizations": "Пользователи всех организаций",
"Verifications": "Verifications",
"Webhooks": "Вебхуки",
"You can only select one physical group": "You can only select one physical group",
"empty": "пустые",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Перенаправление, пожалуйста, подождите.",
"Sign In": "Войти",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Войти с помощью WebAuthn",
"Sign in with {type}": "Войти с помощью {type}",
"Signing in...": "Вход в систему...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Адрес электронной почты для получения тестовых писем",
"Test SMTP Connection": "Тестирование соединения SMTP",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Токен URL (URL-адрес маркера)",
"Token URL - Tooltip": "Токен URL",
"Type": "Тип",
@ -888,7 +891,9 @@
"admin (Shared)": "администратор (общий)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Копировать ссылку",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthn удостоверения",
"input password": "введите пароль"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Тип содержания",
"Content type - Tooltip": "Тип содержимого",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
"Users": "Users",
"Users under all organizations": "Users under all organizations",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "empty",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Redirecting, please wait.",
"Sign In": "Sign In",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Sign in with {type}",
"Signing in...": "Signing in...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Email address to receive test mails",
"Test SMTP Connection": "Test SMTP Connection",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL",
"Type": "Type",
@ -888,7 +891,9 @@
"admin (Shared)": "admin (Shared)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Copy Link",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthn credentials",
"input password": "input password"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Content type",
"Content type - Tooltip": "Content type",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
"Users": "Kullanıcılar",
"Users under all organizations": "Users under all organizations",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "empty",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Yönlendiriliyor, lütfen bekleyiniz.",
"Sign In": "Oturum aç",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "{type} ile giriş yap",
"Signing in...": "Signing in...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Email address to receive test mails",
"Test SMTP Connection": "Test SMTP Connection",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL",
"Type": "Type",
@ -888,7 +891,9 @@
"admin (Shared)": "admin (Shared)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Copy Link",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthn credentials",
"input password": "şifreyi girin"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Content type",
"Content type - Tooltip": "Content type",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
"Users": "Users",
"Users under all organizations": "Users under all organizations",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "empty",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Redirecting, please wait.",
"Sign In": "Sign In",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Sign in with WebAuthn",
"Sign in with {type}": "Sign in with {type}",
"Signing in...": "Signing in...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Email address to receive test mails",
"Test SMTP Connection": "Test SMTP Connection",
"Third-party": "Third-party",
"This field is required": "This field is required",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL",
"Type": "Type",
@ -888,7 +891,9 @@
"admin (Shared)": "admin (Shared)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Copy Link",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthn credentials",
"input password": "input password"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Content type",
"Content type - Tooltip": "Content type",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "Các thẻ mà người dùng thuộc vào, mặc định là \"người dùng bình thường\"",
"Users": "Người dùng",
"Users under all organizations": "Người dùng trong tất cả các tổ chức",
"Verifications": "Verifications",
"Webhooks": "Webhooks",
"You can only select one physical group": "You can only select one physical group",
"empty": "trống",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "Please type an organization to sign in",
"Redirecting, please wait.": "Đang chuyển hướng, vui lòng đợi.",
"Sign In": "Đăng nhập",
"Sign in with Face ID": "Sign in with Face ID",
"Sign in with WebAuthn": "Đăng nhập với WebAuthn",
"Sign in with {type}": "Đăng nhập bằng {type}",
"Signing in...": "Đăng nhập...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "Địa chỉ email để nhận thư kiểm tra",
"Test SMTP Connection": "Kiểm tra kết nối SMTP",
"Third-party": "Bên thứ ba",
"This field is required": "This field is required",
"Token URL": "Đường dẫn mã thông báo",
"Token URL - Tooltip": "Địa chỉ của mã thông báo",
"Type": "Kiểu",
@ -888,7 +891,9 @@
"admin (Shared)": "quản trị viên (Chung)"
},
"record": {
"Is triggered": "Is triggered"
"Is triggered": "Is triggered",
"Object": "Object",
"Response": "Response"
},
"resource": {
"Copy Link": "Sao chép liên kết",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "Chứng chỉ WebAuthn",
"input password": "Nhập mật khẩu"
},
"verification": {
"Receiver": "Receiver"
},
"webhook": {
"Content type": "Loại nội dung",
"Content type - Tooltip": "Loại nội dung",

View File

@ -392,6 +392,7 @@
"User type - Tooltip": "用户所属的标签,默认为\"normal-user\"",
"Users": "用户",
"Users under all organizations": "所有组织里的用户",
"Verifications": "验证",
"Webhooks": "Webhooks",
"You can only select one physical group": "只能选择一个实体组",
"empty": "无",
@ -494,6 +495,7 @@
"Please type an organization to sign in": "请输入要登录的组织",
"Redirecting, please wait.": "正在跳转, 请稍等.",
"Sign In": "登录",
"Sign in with Face ID": "人脸登录",
"Sign in with WebAuthn": "WebAuthn登录",
"Sign in with {type}": "{type}登录",
"Signing in...": "正在登录...",
@ -869,6 +871,7 @@
"Test Email - Tooltip": "接收测试邮件的Email邮箱",
"Test SMTP Connection": "测试SMTP连接",
"Third-party": "第三方",
"This field is required": "此字段是必需的",
"Token URL": "Token URL",
"Token URL - Tooltip": "自定义OAuth的Token URL",
"Type": "类型",
@ -888,7 +891,9 @@
"admin (Shared)": "admin共享"
},
"record": {
"Is triggered": "是否触发"
"Is triggered": "是否触发",
"Object": "实体",
"Response": "响应"
},
"resource": {
"Copy Link": "复制链接",
@ -1159,6 +1164,9 @@
"WebAuthn credentials": "WebAuthn凭据",
"input password": "输入密码"
},
"verification": {
"Receiver": "接收者"
},
"webhook": {
"Content type": "内容类型",
"Content type - Tooltip": "内容类型",

View File

@ -81,10 +81,12 @@ class SignupTable extends React.Component {
{name: "Affiliation", displayName: i18next.t("user:Affiliation")},
{name: "Country/Region", displayName: i18next.t("user:Country/Region")},
{name: "ID card", displayName: i18next.t("user:ID card")},
{name: "Email", displayName: i18next.t("general:Email")},
{name: "Password", displayName: i18next.t("general:Password")},
{name: "Confirm password", displayName: i18next.t("signup:Confirm")},
{name: "Email", displayName: i18next.t("general:Email")},
{name: "Phone", displayName: i18next.t("general:Phone")},
{name: "Email or Phone", displayName: i18next.t("general:Email or Phone")},
{name: "Phone or Email", displayName: i18next.t("general:Phone or Email")},
{name: "Invitation code", displayName: i18next.t("application:Invitation code")},
{name: "Agreement", displayName: i18next.t("signup:Agreement")},
{name: "Text 1", displayName: i18next.t("signup:Text 1")},

View File

@ -183,19 +183,6 @@
dependencies:
"@ctrl/tinycolor" "^3.4.0"
"@ant-design/cssinjs@1.16.1":
version "1.16.1"
resolved "https://registry.yarnpkg.com/@ant-design/cssinjs/-/cssinjs-1.16.1.tgz#0032044db5678dd25ac12def1abb1d52e6a4d583"
integrity sha512-KKVB5Or6BDC1Bo3Y4KMlOkyQU0P+6GTodubrQ9YfrtXG1TgO4wpaEfg9I4ZA49R7M+Ij2KKNwb+5abvmXy6K8w==
dependencies:
"@babel/runtime" "^7.11.1"
"@emotion/hash" "^0.8.0"
"@emotion/unitless" "^0.7.5"
classnames "^2.3.1"
csstype "^3.0.10"
rc-util "^5.35.0"
stylis "^4.0.13"
"@ant-design/cssinjs@^1", "@ant-design/cssinjs@^1.10.1", "@ant-design/cssinjs@^1.5.6":
version "1.10.1"
resolved "https://registry.yarnpkg.com/@ant-design/cssinjs/-/cssinjs-1.10.1.tgz#c9173f38e3d61f0883ca3c17d7cf1e30784e0dd7"
@ -12408,14 +12395,6 @@ rc-util@^5.0.1, rc-util@^5.0.6, rc-util@^5.15.0, rc-util@^5.16.0, rc-util@^5.16.
"@babel/runtime" "^7.18.3"
react-is "^16.12.0"
rc-util@^5.35.0:
version "5.35.0"
resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.35.0.tgz#bed1986248b7be525cc0894109e609ac60207f29"
integrity sha512-MTXlixb3EoSTEchsOc7XWsVyoUQqoCsh2Z1a2IptwNgqleMF6ZgQeY52UzUbNj5CcVBg9YljOWjuOV07jSSm4Q==
dependencies:
"@babel/runtime" "^7.18.3"
react-is "^16.12.0"
rc-virtual-list@^3.4.13, rc-virtual-list@^3.5.1, rc-virtual-list@^3.5.2:
version "3.5.2"
resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.5.2.tgz#5e1028869bae900eacbae6788d4eca7210736006"