mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 21:39:05 +08:00
[feat] ee/google auth implementation (#1775)
* [feat] initial version for google oauth * chore: arranged the sso packages and added prepare request for google auth * feat: added google auth config page and backend to handle the request * chore: code cleanup for domain SSO parsing * Update constants.go * chore: moved redirect sso error * chore: lint issue fixed with domain * chore: added tooltip for enforce sso and few changes to auth domain * chore: moved question mark in enforce sso * fix: resolved pr review comments * chore: fixed type check for saml config * fix: fixed saml config form * chore: added util for transformed form values to samlconfig Co-authored-by: mindhash <mindhash@mindhashs-MacBook-Pro.local> Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com> Co-authored-by: Ankit Nayan <ankit@signoz.io>
This commit is contained in:
parent
1b52edb056
commit
87932de668
@ -93,6 +93,10 @@ func (ah *APIHandler) RegisterRoutes(router *mux.Router) {
|
|||||||
baseapp.OpenAccess(ah.receiveSAML)).
|
baseapp.OpenAccess(ah.receiveSAML)).
|
||||||
Methods(http.MethodPost)
|
Methods(http.MethodPost)
|
||||||
|
|
||||||
|
router.HandleFunc("/api/v1/complete/google",
|
||||||
|
baseapp.OpenAccess(ah.receiveGoogleAuth)).
|
||||||
|
Methods(http.MethodGet)
|
||||||
|
|
||||||
router.HandleFunc("/api/v1/orgs/{orgId}/domains",
|
router.HandleFunc("/api/v1/orgs/{orgId}/domains",
|
||||||
baseapp.AdminAccess(ah.listDomainsByOrg)).
|
baseapp.AdminAccess(ah.listDomainsByOrg)).
|
||||||
Methods(http.MethodGet)
|
Methods(http.MethodGet)
|
||||||
|
@ -8,9 +8,6 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"go.signoz.io/signoz/ee/query-service/constants"
|
"go.signoz.io/signoz/ee/query-service/constants"
|
||||||
"go.signoz.io/signoz/ee/query-service/model"
|
"go.signoz.io/signoz/ee/query-service/model"
|
||||||
@ -184,114 +181,152 @@ func (ah *APIHandler) precheckLogin(w http.ResponseWriter, r *http.Request) {
|
|||||||
ah.Respond(w, resp)
|
ah.Respond(w, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ah *APIHandler) receiveSAML(w http.ResponseWriter, r *http.Request) {
|
func handleSsoError(w http.ResponseWriter, r *http.Request, redirectURL string) {
|
||||||
// this is the source url that initiated the login request
|
ssoError := []byte("Login failed. Please contact your system administrator")
|
||||||
|
dst := make([]byte, base64.StdEncoding.EncodedLen(len(ssoError)))
|
||||||
|
base64.StdEncoding.Encode(dst, ssoError)
|
||||||
|
|
||||||
|
http.Redirect(w, r, fmt.Sprintf("%s?ssoerror=%s", redirectURL, string(dst)), http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
|
||||||
|
// receiveGoogleAuth completes google OAuth response and forwards a request
|
||||||
|
// to front-end to sign user in
|
||||||
|
func (ah *APIHandler) receiveGoogleAuth(w http.ResponseWriter, r *http.Request) {
|
||||||
redirectUri := constants.GetDefaultSiteURL()
|
redirectUri := constants.GetDefaultSiteURL()
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
var apierr basemodel.BaseApiError
|
|
||||||
|
|
||||||
redirectOnError := func() {
|
|
||||||
ssoError := []byte("Login failed. Please contact your system administrator")
|
|
||||||
dst := make([]byte, base64.StdEncoding.EncodedLen(len(ssoError)))
|
|
||||||
base64.StdEncoding.Encode(dst, ssoError)
|
|
||||||
|
|
||||||
http.Redirect(w, r, fmt.Sprintf("%s?ssoerror=%s", redirectUri, string(dst)), http.StatusMovedPermanently)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ah.CheckFeature(model.SSO) {
|
if !ah.CheckFeature(model.SSO) {
|
||||||
zap.S().Errorf("[ReceiveSAML] sso requested but feature unavailable %s in org domain %s", model.SSO)
|
zap.S().Errorf("[receiveGoogleAuth] sso requested but feature unavailable %s in org domain %s", model.SSO)
|
||||||
http.Redirect(w, r, fmt.Sprintf("%s?ssoerror=%s", redirectUri, "feature unavailable, please upgrade your billing plan to access this feature"), http.StatusMovedPermanently)
|
http.Redirect(w, r, fmt.Sprintf("%s?ssoerror=%s", redirectUri, "feature unavailable, please upgrade your billing plan to access this feature"), http.StatusMovedPermanently)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := r.ParseForm()
|
q := r.URL.Query()
|
||||||
if err != nil {
|
if errType := q.Get("error"); errType != "" {
|
||||||
zap.S().Errorf("[ReceiveSAML] failed to process response - invalid response from IDP", err, r)
|
zap.S().Errorf("[receiveGoogleAuth] failed to login with google auth", q.Get("error_description"))
|
||||||
redirectOnError()
|
http.Redirect(w, r, fmt.Sprintf("%s?ssoerror=%s", redirectUri, "failed to login through SSO "), http.StatusMovedPermanently)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// the relay state is sent when a login request is submitted to
|
relayState := q.Get("state")
|
||||||
// Idp.
|
zap.S().Debug("[receiveGoogleAuth] relay state received", zap.String("state", relayState))
|
||||||
relayState := r.FormValue("RelayState")
|
|
||||||
zap.S().Debug("[ReceiveML] relay state", zap.String("relayState", relayState))
|
|
||||||
|
|
||||||
parsedState, err := url.Parse(relayState)
|
parsedState, err := url.Parse(relayState)
|
||||||
if err != nil || relayState == "" {
|
if err != nil || relayState == "" {
|
||||||
zap.S().Errorf("[ReceiveSAML] failed to process response - invalid response from IDP", err, r)
|
zap.S().Errorf("[receiveGoogleAuth] failed to process response - invalid response from IDP", err, r)
|
||||||
redirectOnError()
|
handleSsoError(w, r, redirectUri)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// upgrade redirect url from the relay state for better accuracy
|
// upgrade redirect url from the relay state for better accuracy
|
||||||
redirectUri = fmt.Sprintf("%s://%s%s", parsedState.Scheme, parsedState.Host, "/login")
|
redirectUri = fmt.Sprintf("%s://%s%s", parsedState.Scheme, parsedState.Host, "/login")
|
||||||
|
|
||||||
// derive domain id from relay state now
|
// fetch domain by parsing relay state.
|
||||||
var domainIdStr string
|
domain, err := ah.AppDao().GetDomainFromSsoResponse(ctx, parsedState)
|
||||||
for k, v := range parsedState.Query() {
|
|
||||||
if k == "domainId" && len(v) > 0 {
|
|
||||||
domainIdStr = strings.Replace(v[0], ":", "-", -1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
domainId, err := uuid.Parse(domainIdStr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.S().Errorf("[ReceiveSAML] failed to process request- failed to parse domain id ifrom relay", zap.Error(err))
|
handleSsoError(w, r, redirectUri)
|
||||||
redirectOnError()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
domain, apierr := ah.AppDao().GetDomain(ctx, domainId)
|
// now that we have domain, use domain to fetch sso settings.
|
||||||
if (apierr != nil) || domain == nil {
|
// prepare google callback handler using parsedState -
|
||||||
zap.S().Errorf("[ReceiveSAML] failed to process request- invalid domain", domainIdStr, zap.Error(apierr))
|
// which contains redirect URL (front-end endpoint)
|
||||||
redirectOnError()
|
callbackHandler, err := domain.PrepareGoogleOAuthProvider(parsedState)
|
||||||
|
|
||||||
|
identity, err := callbackHandler.HandleCallback(r)
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Errorf("[receiveGoogleAuth] failed to process HandleCallback ", domain.String(), zap.Error(err))
|
||||||
|
handleSsoError(w, r, redirectUri)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nextPage, err := ah.AppDao().PrepareSsoRedirect(ctx, redirectUri, identity.Email)
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Errorf("[receiveGoogleAuth] failed to generate redirect URI after successful login ", domain.String(), zap.Error(err))
|
||||||
|
handleSsoError(w, r, redirectUri)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
http.Redirect(w, r, nextPage, http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// receiveSAML completes a SAML request and gets user logged in
|
||||||
|
func (ah *APIHandler) receiveSAML(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// this is the source url that initiated the login request
|
||||||
|
redirectUri := constants.GetDefaultSiteURL()
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
|
||||||
|
if !ah.CheckFeature(model.SSO) {
|
||||||
|
zap.S().Errorf("[receiveSAML] sso requested but feature unavailable %s in org domain %s", model.SSO)
|
||||||
|
http.Redirect(w, r, fmt.Sprintf("%s?ssoerror=%s", redirectUri, "feature unavailable, please upgrade your billing plan to access this feature"), http.StatusMovedPermanently)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := r.ParseForm()
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Errorf("[receiveSAML] failed to process response - invalid response from IDP", err, r)
|
||||||
|
handleSsoError(w, r, redirectUri)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// the relay state is sent when a login request is submitted to
|
||||||
|
// Idp.
|
||||||
|
relayState := r.FormValue("RelayState")
|
||||||
|
zap.S().Debug("[receiveML] relay state", zap.String("relayState", relayState))
|
||||||
|
|
||||||
|
parsedState, err := url.Parse(relayState)
|
||||||
|
if err != nil || relayState == "" {
|
||||||
|
zap.S().Errorf("[receiveSAML] failed to process response - invalid response from IDP", err, r)
|
||||||
|
handleSsoError(w, r, redirectUri)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// upgrade redirect url from the relay state for better accuracy
|
||||||
|
redirectUri = fmt.Sprintf("%s://%s%s", parsedState.Scheme, parsedState.Host, "/login")
|
||||||
|
|
||||||
|
// fetch domain by parsing relay state.
|
||||||
|
domain, err := ah.AppDao().GetDomainFromSsoResponse(ctx, parsedState)
|
||||||
|
if err != nil {
|
||||||
|
handleSsoError(w, r, redirectUri)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
sp, err := domain.PrepareSamlRequest(parsedState)
|
sp, err := domain.PrepareSamlRequest(parsedState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.S().Errorf("[ReceiveSAML] failed to prepare saml request for domain (%s): %v", domainId, err)
|
zap.S().Errorf("[receiveSAML] failed to prepare saml request for domain (%s): %v", domain.String(), err)
|
||||||
redirectOnError()
|
handleSsoError(w, r, redirectUri)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
assertionInfo, err := sp.RetrieveAssertionInfo(r.FormValue("SAMLResponse"))
|
assertionInfo, err := sp.RetrieveAssertionInfo(r.FormValue("SAMLResponse"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.S().Errorf("[ReceiveSAML] failed to retrieve assertion info from saml response for organization (%s): %v", domainId, err)
|
zap.S().Errorf("[receiveSAML] failed to retrieve assertion info from saml response for organization (%s): %v", domain.String(), err)
|
||||||
redirectOnError()
|
handleSsoError(w, r, redirectUri)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if assertionInfo.WarningInfo.InvalidTime {
|
if assertionInfo.WarningInfo.InvalidTime {
|
||||||
zap.S().Errorf("[ReceiveSAML] expired saml response for organization (%s): %v", domainId, err)
|
zap.S().Errorf("[receiveSAML] expired saml response for organization (%s): %v", domain.String(), err)
|
||||||
redirectOnError()
|
handleSsoError(w, r, redirectUri)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
email := assertionInfo.NameID
|
email := assertionInfo.NameID
|
||||||
|
if email == "" {
|
||||||
// user email found, now start preparing jwt response
|
zap.S().Errorf("[receiveSAML] invalid email in the SSO response (%s)", domain.String())
|
||||||
userPayload, baseapierr := ah.AppDao().GetUserByEmail(ctx, email)
|
handleSsoError(w, r, redirectUri)
|
||||||
if baseapierr != nil {
|
|
||||||
zap.S().Errorf("[ReceiveSAML] failed to find or register a new user for email %s and org %s", email, domainId, zap.Error(baseapierr.Err))
|
|
||||||
redirectOnError()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenStore, err := baseauth.GenerateJWTForUser(&userPayload.User)
|
nextPage, err := ah.AppDao().PrepareSsoRedirect(ctx, redirectUri, email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.S().Errorf("[ReceiveSAML] failed to generate access token for email %s and org %s", email, domainId, zap.Error(err))
|
zap.S().Errorf("[receiveSAML] failed to generate redirect URI after successful login ", domain.String(), zap.Error(err))
|
||||||
redirectOnError()
|
handleSsoError(w, r, redirectUri)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
userID := userPayload.User.Id
|
http.Redirect(w, r, nextPage, http.StatusSeeOther)
|
||||||
nextPage := fmt.Sprintf("%s?jwt=%s&usr=%s&refreshjwt=%s",
|
|
||||||
redirectUri,
|
|
||||||
tokenStore.AccessJwt,
|
|
||||||
userID,
|
|
||||||
tokenStore.RefreshJwt)
|
|
||||||
|
|
||||||
http.Redirect(w, r, nextPage, http.StatusMovedPermanently)
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package dao
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net/url"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"go.signoz.io/signoz/ee/query-service/model"
|
"go.signoz.io/signoz/ee/query-service/model"
|
||||||
@ -22,7 +22,9 @@ type ModelDao interface {
|
|||||||
// auth methods
|
// auth methods
|
||||||
PrecheckLogin(ctx context.Context, email, sourceUrl string) (*model.PrecheckResponse, basemodel.BaseApiError)
|
PrecheckLogin(ctx context.Context, email, sourceUrl string) (*model.PrecheckResponse, basemodel.BaseApiError)
|
||||||
CanUsePassword(ctx context.Context, email string) (bool, basemodel.BaseApiError)
|
CanUsePassword(ctx context.Context, email string) (bool, basemodel.BaseApiError)
|
||||||
|
PrepareSsoRedirect(ctx context.Context, redirectUri, email string) (redirectURL string, apierr basemodel.BaseApiError)
|
||||||
|
GetDomainFromSsoResponse(ctx context.Context, relayState *url.URL) (*model.OrgDomain, error)
|
||||||
|
|
||||||
// org domain (auth domains) CRUD ops
|
// org domain (auth domains) CRUD ops
|
||||||
ListDomains(ctx context.Context, orgId string) ([]model.OrgDomain, basemodel.BaseApiError)
|
ListDomains(ctx context.Context, orgId string) ([]model.OrgDomain, basemodel.BaseApiError)
|
||||||
GetDomain(ctx context.Context, id uuid.UUID) (*model.OrgDomain, basemodel.BaseApiError)
|
GetDomain(ctx context.Context, id uuid.UUID) (*model.OrgDomain, basemodel.BaseApiError)
|
||||||
|
@ -10,9 +10,33 @@ import (
|
|||||||
"go.signoz.io/signoz/ee/query-service/model"
|
"go.signoz.io/signoz/ee/query-service/model"
|
||||||
baseconst "go.signoz.io/signoz/pkg/query-service/constants"
|
baseconst "go.signoz.io/signoz/pkg/query-service/constants"
|
||||||
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
||||||
|
baseauth "go.signoz.io/signoz/pkg/query-service/auth"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PrepareSsoRedirect prepares redirect page link after SSO response
|
||||||
|
// is successfully parsed (i.e. valid email is available)
|
||||||
|
func (m *modelDao) PrepareSsoRedirect(ctx context.Context, redirectUri, email string) (redirectURL string, apierr basemodel.BaseApiError) {
|
||||||
|
|
||||||
|
userPayload, apierr := m.GetUserByEmail(ctx, email)
|
||||||
|
if !apierr.IsNil() {
|
||||||
|
zap.S().Errorf(" failed to get user with email received from auth provider", apierr.Error())
|
||||||
|
return "", model.BadRequestStr("invalid user email received from the auth provider")
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenStore, err := baseauth.GenerateJWTForUser(&userPayload.User)
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Errorf("failed to generate token for SSO login user", err)
|
||||||
|
return "", model.InternalErrorStr("failed to generate token for the user")
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%s?jwt=%s&usr=%s&refreshjwt=%s",
|
||||||
|
redirectUri,
|
||||||
|
tokenStore.AccessJwt,
|
||||||
|
userPayload.User.Id,
|
||||||
|
tokenStore.RefreshJwt), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *modelDao) CanUsePassword(ctx context.Context, email string) (bool, basemodel.BaseApiError) {
|
func (m *modelDao) CanUsePassword(ctx context.Context, email string) (bool, basemodel.BaseApiError) {
|
||||||
domain, apierr := m.GetDomainByEmail(ctx, email)
|
domain, apierr := m.GetDomainByEmail(ctx, email)
|
||||||
if apierr != nil {
|
if apierr != nil {
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -25,6 +26,34 @@ type StoredDomain struct {
|
|||||||
UpdatedAt int64 `db:"updated_at"`
|
UpdatedAt int64 `db:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDomainFromSsoResponse uses relay state received from IdP to fetch
|
||||||
|
// user domain. The domain is further used to process validity of the response.
|
||||||
|
// when sending login request to IdP we send relay state as URL (site url)
|
||||||
|
// with domainId as query parameter.
|
||||||
|
func (m *modelDao) GetDomainFromSsoResponse(ctx context.Context, relayState *url.URL) (*model.OrgDomain, error) {
|
||||||
|
// derive domain id from relay state now
|
||||||
|
var domainIdStr string
|
||||||
|
for k, v := range relayState.Query() {
|
||||||
|
if k == "domainId" && len(v) > 0 {
|
||||||
|
domainIdStr = strings.Replace(v[0], ":", "-", -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
domainId, err := uuid.Parse(domainIdStr)
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Errorf("failed to parse domain id from relay state", err)
|
||||||
|
return nil, fmt.Errorf("failed to parse response from IdP response")
|
||||||
|
}
|
||||||
|
|
||||||
|
domain, err := m.GetDomain(ctx, domainId)
|
||||||
|
if (err != nil) || domain == nil {
|
||||||
|
zap.S().Errorf("failed to find domain received in IdP response", err.Error())
|
||||||
|
return nil, fmt.Errorf("invalid credentials")
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetDomain returns org domain for a given domain id
|
// GetDomain returns org domain for a given domain id
|
||||||
func (m *modelDao) GetDomain(ctx context.Context, id uuid.UUID) (*model.OrgDomain, basemodel.BaseApiError) {
|
func (m *modelDao) GetDomain(ctx context.Context, id uuid.UUID) (*model.OrgDomain, basemodel.BaseApiError) {
|
||||||
|
|
||||||
|
@ -9,8 +9,10 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
saml2 "github.com/russellhaering/gosaml2"
|
saml2 "github.com/russellhaering/gosaml2"
|
||||||
"go.signoz.io/signoz/ee/query-service/saml"
|
"go.signoz.io/signoz/ee/query-service/sso/saml"
|
||||||
|
"go.signoz.io/signoz/ee/query-service/sso"
|
||||||
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SSOType string
|
type SSOType string
|
||||||
@ -20,12 +22,6 @@ const (
|
|||||||
GoogleAuth SSOType = "GOOGLE_AUTH"
|
GoogleAuth SSOType = "GOOGLE_AUTH"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SamlConfig struct {
|
|
||||||
SamlEntity string `json:"samlEntity"`
|
|
||||||
SamlIdp string `json:"samlIdp"`
|
|
||||||
SamlCert string `json:"samlCert"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// OrgDomain identify org owned web domains for auth and other purposes
|
// OrgDomain identify org owned web domains for auth and other purposes
|
||||||
type OrgDomain struct {
|
type OrgDomain struct {
|
||||||
Id uuid.UUID `json:"id"`
|
Id uuid.UUID `json:"id"`
|
||||||
@ -33,10 +29,17 @@ type OrgDomain struct {
|
|||||||
OrgId string `json:"orgId"`
|
OrgId string `json:"orgId"`
|
||||||
SsoEnabled bool `json:"ssoEnabled"`
|
SsoEnabled bool `json:"ssoEnabled"`
|
||||||
SsoType SSOType `json:"ssoType"`
|
SsoType SSOType `json:"ssoType"`
|
||||||
|
|
||||||
SamlConfig *SamlConfig `json:"samlConfig"`
|
SamlConfig *SamlConfig `json:"samlConfig"`
|
||||||
|
GoogleAuthConfig *GoogleOAuthConfig `json:"googleAuthConfig"`
|
||||||
|
|
||||||
Org *basemodel.Organization
|
Org *basemodel.Organization
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (od *OrgDomain) String() string {
|
||||||
|
return fmt.Sprintf("[%s]%s-%s ", od.Name, od.Id.String(), od.SsoType)
|
||||||
|
}
|
||||||
|
|
||||||
// Valid is used a pipeline function to check if org domain
|
// Valid is used a pipeline function to check if org domain
|
||||||
// loaded from db is valid
|
// loaded from db is valid
|
||||||
func (od *OrgDomain) Valid(err error) error {
|
func (od *OrgDomain) Valid(err error) error {
|
||||||
@ -97,6 +100,16 @@ func (od *OrgDomain) GetSAMLCert() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PrepareGoogleOAuthProvider creates GoogleProvider that is used in
|
||||||
|
// requesting OAuth and also used in processing response from google
|
||||||
|
func (od *OrgDomain) PrepareGoogleOAuthProvider(siteUrl *url.URL) (sso.OAuthCallbackProvider, error) {
|
||||||
|
if od.GoogleAuthConfig == nil {
|
||||||
|
return nil, fmt.Errorf("Google auth is not setup correctly for this domain")
|
||||||
|
}
|
||||||
|
|
||||||
|
return od.GoogleAuthConfig.GetProvider(od.Name, siteUrl)
|
||||||
|
}
|
||||||
|
|
||||||
// PrepareSamlRequest creates a request accordingly gosaml2
|
// PrepareSamlRequest creates a request accordingly gosaml2
|
||||||
func (od *OrgDomain) PrepareSamlRequest(siteUrl *url.URL) (*saml2.SAMLServiceProvider, error) {
|
func (od *OrgDomain) PrepareSamlRequest(siteUrl *url.URL) (*saml2.SAMLServiceProvider, error) {
|
||||||
|
|
||||||
@ -124,19 +137,48 @@ func (od *OrgDomain) PrepareSamlRequest(siteUrl *url.URL) (*saml2.SAMLServicePro
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (od *OrgDomain) BuildSsoUrl(siteUrl *url.URL) (ssoUrl string, err error) {
|
func (od *OrgDomain) BuildSsoUrl(siteUrl *url.URL) (ssoUrl string, err error) {
|
||||||
|
|
||||||
sp, err := od.PrepareSamlRequest(siteUrl)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmtDomainId := strings.Replace(od.Id.String(), "-", ":", -1)
|
fmtDomainId := strings.Replace(od.Id.String(), "-", ":", -1)
|
||||||
|
|
||||||
|
// build redirect url from window.location sent by frontend
|
||||||
|
redirectURL := fmt.Sprintf("%s://%s%s", siteUrl.Scheme, siteUrl.Host, siteUrl.Path)
|
||||||
|
|
||||||
|
// prepare state that gets relayed back when the auth provider
|
||||||
|
// calls back our url. here we pass the app url (where signoz runs)
|
||||||
|
// and the domain Id. The domain Id helps in identifying sso config
|
||||||
|
// when the call back occurs and the app url is useful in redirecting user
|
||||||
|
// back to the right path.
|
||||||
|
// why do we need to pass app url? the callback typically is handled by backend
|
||||||
|
// and sometimes backend might right at a different port or is unaware of frontend
|
||||||
|
// endpoint (unless SITE_URL param is set). hence, we receive this build sso request
|
||||||
|
// along with frontend window.location and use it to relay the information through
|
||||||
|
// auth provider to the backend (HandleCallback or HandleSSO method).
|
||||||
|
relayState := fmt.Sprintf("%s?domainId=%s", redirectURL, fmtDomainId)
|
||||||
|
|
||||||
|
|
||||||
|
switch (od.SsoType) {
|
||||||
|
case SAML:
|
||||||
|
|
||||||
|
sp, err := od.PrepareSamlRequest(siteUrl)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sp.BuildAuthURL(relayState)
|
||||||
|
|
||||||
|
case GoogleAuth:
|
||||||
|
|
||||||
|
googleProvider, err := od.PrepareGoogleOAuthProvider(siteUrl)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return googleProvider.BuildAuthURL(relayState)
|
||||||
|
|
||||||
|
default:
|
||||||
|
zap.S().Errorf("found unsupported SSO config for the org domain", zap.String("orgDomain", od.Name))
|
||||||
|
return "", fmt.Errorf("unsupported SSO config for the domain")
|
||||||
|
}
|
||||||
|
|
||||||
relayState := fmt.Sprintf("%s://%s%s?domainId=%s",
|
|
||||||
siteUrl.Scheme,
|
|
||||||
siteUrl.Host,
|
|
||||||
siteUrl.Path,
|
|
||||||
fmtDomainId)
|
|
||||||
|
|
||||||
return sp.BuildAuthURL(relayState)
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
basemodel "go.signoz.io/signoz/pkg/query-service/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -44,6 +45,14 @@ func BadRequest(err error) *ApiError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BadRequestStr returns a ApiError object of bad request for string input
|
||||||
|
func BadRequestStr(s string) *ApiError {
|
||||||
|
return &ApiError{
|
||||||
|
Typ: basemodel.ErrorBadData,
|
||||||
|
Err: fmt.Errorf(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// InternalError returns a ApiError object of internal type
|
// InternalError returns a ApiError object of internal type
|
||||||
func InternalError(err error) *ApiError {
|
func InternalError(err error) *ApiError {
|
||||||
return &ApiError{
|
return &ApiError{
|
||||||
@ -52,6 +61,14 @@ func InternalError(err error) *ApiError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// InternalErrorStr returns a ApiError object of internal type for string input
|
||||||
|
func InternalErrorStr(s string) *ApiError {
|
||||||
|
return &ApiError{
|
||||||
|
Typ: basemodel.ErrorInternal,
|
||||||
|
Err: fmt.Errorf(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
var (
|
var (
|
||||||
ErrorNone basemodel.ErrorType = ""
|
ErrorNone basemodel.ErrorType = ""
|
||||||
ErrorTimeout basemodel.ErrorType = "timeout"
|
ErrorTimeout basemodel.ErrorType = "timeout"
|
||||||
|
68
ee/query-service/model/sso.go
Normal file
68
ee/query-service/model/sso.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"context"
|
||||||
|
"net/url"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
"github.com/coreos/go-oidc/v3/oidc"
|
||||||
|
"go.signoz.io/signoz/ee/query-service/sso"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SamlConfig contans SAML params to generate and respond to the requests
|
||||||
|
// from SAML provider
|
||||||
|
type SamlConfig struct {
|
||||||
|
SamlEntity string `json:"samlEntity"`
|
||||||
|
SamlIdp string `json:"samlIdp"`
|
||||||
|
SamlCert string `json:"samlCert"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoogleOauthConfig contains a generic config to support oauth
|
||||||
|
type GoogleOAuthConfig struct {
|
||||||
|
ClientID string `json:"clientId"`
|
||||||
|
ClientSecret string `json:"clientSecret"`
|
||||||
|
RedirectURI string `json:"redirectURI"`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const (
|
||||||
|
googleIssuerURL = "https://accounts.google.com"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (g *GoogleOAuthConfig) GetProvider(domain string, siteUrl *url.URL) (sso.OAuthCallbackProvider, error) {
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
provider, err := oidc.NewProvider(ctx, googleIssuerURL)
|
||||||
|
if err != nil {
|
||||||
|
cancel()
|
||||||
|
return nil, fmt.Errorf("failed to get provider: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// default to email and profile scope as we just use google auth
|
||||||
|
// to verify identity and start a session.
|
||||||
|
scopes := []string{"email"}
|
||||||
|
|
||||||
|
// this is the url google will call after login completion
|
||||||
|
redirectURL := fmt.Sprintf("%s://%s/%s",
|
||||||
|
siteUrl.Scheme,
|
||||||
|
siteUrl.Host,
|
||||||
|
"api/v1/complete/google")
|
||||||
|
|
||||||
|
return &sso.GoogleOAuthProvider{
|
||||||
|
RedirectURI: g.RedirectURI,
|
||||||
|
OAuth2Config: &oauth2.Config{
|
||||||
|
ClientID: g.ClientID,
|
||||||
|
ClientSecret: g.ClientSecret,
|
||||||
|
Endpoint: provider.Endpoint(),
|
||||||
|
Scopes: scopes,
|
||||||
|
RedirectURL: redirectURL,
|
||||||
|
},
|
||||||
|
Verifier: provider.Verifier(
|
||||||
|
&oidc.Config{ClientID: g.ClientID},
|
||||||
|
),
|
||||||
|
Cancel: cancel,
|
||||||
|
HostedDomain: domain,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
92
ee/query-service/sso/google.go
Normal file
92
ee/query-service/sso/google.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package sso
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"errors"
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"github.com/coreos/go-oidc/v3/oidc"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GoogleOAuthProvider struct {
|
||||||
|
RedirectURI string
|
||||||
|
OAuth2Config *oauth2.Config
|
||||||
|
Verifier *oidc.IDTokenVerifier
|
||||||
|
Cancel context.CancelFunc
|
||||||
|
HostedDomain string
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (g *GoogleOAuthProvider) BuildAuthURL(state string) (string, error) {
|
||||||
|
var opts []oauth2.AuthCodeOption
|
||||||
|
|
||||||
|
// set hosted domain. google supports multiple hosted domains but in our case
|
||||||
|
// we have one config per host domain.
|
||||||
|
opts = append(opts, oauth2.SetAuthURLParam("hd", g.HostedDomain))
|
||||||
|
|
||||||
|
return g.OAuth2Config.AuthCodeURL(state, opts...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type oauth2Error struct{
|
||||||
|
error string
|
||||||
|
errorDescription string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *oauth2Error) Error() string {
|
||||||
|
if e.errorDescription == "" {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
return e.error + ": " + e.errorDescription
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GoogleOAuthProvider) HandleCallback(r *http.Request) (identity *SSOIdentity, err error) {
|
||||||
|
q := r.URL.Query()
|
||||||
|
if errType := q.Get("error"); errType != "" {
|
||||||
|
return identity, &oauth2Error{errType, q.Get("error_description")}
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := g.OAuth2Config.Exchange(r.Context(), q.Get("code"))
|
||||||
|
if err != nil {
|
||||||
|
return identity, fmt.Errorf("google: failed to get token: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return g.createIdentity(r.Context(), token)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (g *GoogleOAuthProvider) createIdentity(ctx context.Context, token *oauth2.Token) (identity *SSOIdentity, err error) {
|
||||||
|
rawIDToken, ok := token.Extra("id_token").(string)
|
||||||
|
if !ok {
|
||||||
|
return identity, errors.New("google: no id_token in token response")
|
||||||
|
}
|
||||||
|
idToken, err := g.Verifier.Verify(ctx, rawIDToken)
|
||||||
|
if err != nil {
|
||||||
|
return identity, fmt.Errorf("google: failed to verify ID Token: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var claims struct {
|
||||||
|
Username string `json:"name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
EmailVerified bool `json:"email_verified"`
|
||||||
|
HostedDomain string `json:"hd"`
|
||||||
|
}
|
||||||
|
if err := idToken.Claims(&claims); err != nil {
|
||||||
|
return identity, fmt.Errorf("oidc: failed to decode claims: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if claims.HostedDomain != g.HostedDomain {
|
||||||
|
return identity, fmt.Errorf("oidc: unexpected hd claim %v", claims.HostedDomain)
|
||||||
|
}
|
||||||
|
|
||||||
|
identity = &SSOIdentity{
|
||||||
|
UserID: idToken.Subject,
|
||||||
|
Username: claims.Username,
|
||||||
|
Email: claims.Email,
|
||||||
|
EmailVerified: claims.EmailVerified,
|
||||||
|
ConnectorData: []byte(token.RefreshToken),
|
||||||
|
}
|
||||||
|
|
||||||
|
return identity, nil
|
||||||
|
}
|
||||||
|
|
31
ee/query-service/sso/model.go
Normal file
31
ee/query-service/sso/model.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package sso
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SSOIdentity contains details of user received from SSO provider
|
||||||
|
type SSOIdentity struct {
|
||||||
|
UserID string
|
||||||
|
Username string
|
||||||
|
PreferredUsername string
|
||||||
|
Email string
|
||||||
|
EmailVerified bool
|
||||||
|
ConnectorData []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// OAuthCallbackProvider is an interface implemented by connectors which use an OAuth
|
||||||
|
// style redirect flow to determine user information.
|
||||||
|
type OAuthCallbackProvider interface {
|
||||||
|
// The initial URL user would be redirect to.
|
||||||
|
// OAuth2 implementations support various scopes but we only need profile and user as
|
||||||
|
// the roles are still being managed in SigNoz.
|
||||||
|
BuildAuthURL(state string) (string, error)
|
||||||
|
|
||||||
|
// Handle the callback to the server (after login at oauth provider site)
|
||||||
|
// and return a email identity.
|
||||||
|
// At the moment we dont support auto signup flow (based on domain), so
|
||||||
|
// the full identity (including name, group etc) is not required outside of the
|
||||||
|
// connector
|
||||||
|
HandleCallback(r *http.Request) (identity *SSOIdentity, err error)
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { Button, Space, Typography } from 'antd';
|
import { Button, Space, Typography } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { IconContainer, TitleContainer } from './styles';
|
import { IconContainer, TitleContainer, TitleText } from './styles';
|
||||||
|
|
||||||
function Row({
|
function Row({
|
||||||
onClickHandler,
|
onClickHandler,
|
||||||
@ -16,8 +16,8 @@ function Row({
|
|||||||
<IconContainer>{Icon}</IconContainer>
|
<IconContainer>{Icon}</IconContainer>
|
||||||
|
|
||||||
<TitleContainer>
|
<TitleContainer>
|
||||||
<Typography>{title}</Typography>
|
<TitleText>{title}</TitleText>
|
||||||
<Typography.Text italic>{subTitle}</Typography.Text>
|
<Typography.Text>{subTitle}</Typography.Text>
|
||||||
</TitleContainer>
|
</TitleContainer>
|
||||||
|
|
||||||
<Button disabled={isDisabled} onClick={onClickHandler} type="primary">
|
<Button disabled={isDisabled} onClick={onClickHandler} type="primary">
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Typography } from 'antd';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const TitleContainer = styled.div`
|
export const TitleContainer = styled.div`
|
||||||
@ -9,3 +10,7 @@ export const TitleContainer = styled.div`
|
|||||||
export const IconContainer = styled.div`
|
export const IconContainer = styled.div`
|
||||||
min-width: 70px;
|
min-width: 70px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const TitleText = styled(Typography)`
|
||||||
|
font-weight: bold;
|
||||||
|
`;
|
||||||
|
@ -1,34 +1,51 @@
|
|||||||
import { GoogleSquareFilled, KeyOutlined } from '@ant-design/icons';
|
import { GoogleSquareFilled, KeyOutlined } from '@ant-design/icons';
|
||||||
import { Space, Typography } from 'antd';
|
import { Typography } from 'antd';
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
|
import { AuthDomain, GOOGLE_AUTH, SAML } from 'types/api/SAML/listDomain';
|
||||||
|
|
||||||
import Row, { RowProps } from './Row';
|
import Row, { RowProps } from './Row';
|
||||||
import { RowContainer } from './styles';
|
import { RowContainer, RowSpace } from './styles';
|
||||||
|
|
||||||
function Create({
|
function Create({
|
||||||
|
ssoMethod,
|
||||||
|
assignSsoMethod,
|
||||||
setIsSettingsOpen,
|
setIsSettingsOpen,
|
||||||
setIsEditModalOpen,
|
setIsEditModalOpen,
|
||||||
}: CreateProps): JSX.Element {
|
}: CreateProps): JSX.Element {
|
||||||
const onConfigureClickHandler = useCallback(() => {
|
const onGoogleAuthClickHandler = useCallback(() => {
|
||||||
console.log('Configure Clicked');
|
assignSsoMethod(GOOGLE_AUTH);
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onEditSAMLHandler = useCallback(() => {
|
|
||||||
setIsSettingsOpen(false);
|
setIsSettingsOpen(false);
|
||||||
setIsEditModalOpen(true);
|
setIsEditModalOpen(true);
|
||||||
}, [setIsSettingsOpen, setIsEditModalOpen]);
|
}, [assignSsoMethod, setIsSettingsOpen, setIsEditModalOpen]);
|
||||||
|
|
||||||
|
const onEditSAMLHandler = useCallback(() => {
|
||||||
|
assignSsoMethod(SAML);
|
||||||
|
setIsSettingsOpen(false);
|
||||||
|
setIsEditModalOpen(true);
|
||||||
|
}, [assignSsoMethod, setIsSettingsOpen, setIsEditModalOpen]);
|
||||||
|
|
||||||
|
const ConfigureButtonText = useMemo(() => {
|
||||||
|
switch (ssoMethod) {
|
||||||
|
case GOOGLE_AUTH:
|
||||||
|
return 'Edit Google Auth';
|
||||||
|
case SAML:
|
||||||
|
return 'Edit SAML';
|
||||||
|
default:
|
||||||
|
return 'Get Started';
|
||||||
|
}
|
||||||
|
}, [ssoMethod]);
|
||||||
|
|
||||||
const data: RowProps[] = [
|
const data: RowProps[] = [
|
||||||
{
|
{
|
||||||
buttonText: 'Configure',
|
buttonText: ConfigureButtonText,
|
||||||
Icon: <GoogleSquareFilled style={{ fontSize: '37px' }} />,
|
Icon: <GoogleSquareFilled style={{ fontSize: '37px' }} />,
|
||||||
title: 'Google Apps Authentication',
|
title: 'Google Apps Authentication',
|
||||||
subTitle: 'Let members sign-in with a Google account',
|
subTitle: 'Let members sign-in with a Google account',
|
||||||
onClickHandler: onConfigureClickHandler,
|
onClickHandler: onGoogleAuthClickHandler,
|
||||||
isDisabled: true,
|
isDisabled: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
buttonText: 'Edit SAML',
|
buttonText: ConfigureButtonText,
|
||||||
Icon: <KeyOutlined style={{ fontSize: '37px' }} />,
|
Icon: <KeyOutlined style={{ fontSize: '37px' }} />,
|
||||||
onClickHandler: onEditSAMLHandler,
|
onClickHandler: onEditSAMLHandler,
|
||||||
subTitle: 'Azure, Active Directory, Okta or your custom SAML 2.0 solution',
|
subTitle: 'Azure, Active Directory, Okta or your custom SAML 2.0 solution',
|
||||||
@ -45,7 +62,7 @@ function Create({
|
|||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
|
|
||||||
<RowContainer>
|
<RowContainer>
|
||||||
<Space direction="vertical">
|
<RowSpace direction="vertical">
|
||||||
{data.map((rowData) => (
|
{data.map((rowData) => (
|
||||||
<Row
|
<Row
|
||||||
Icon={rowData.Icon}
|
Icon={rowData.Icon}
|
||||||
@ -57,13 +74,15 @@ function Create({
|
|||||||
isDisabled={rowData.isDisabled}
|
isDisabled={rowData.isDisabled}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Space>
|
</RowSpace>
|
||||||
</RowContainer>
|
</RowContainer>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CreateProps {
|
interface CreateProps {
|
||||||
|
ssoMethod: AuthDomain['ssoType'];
|
||||||
|
assignSsoMethod: (value: AuthDomain['ssoType']) => void;
|
||||||
setIsSettingsOpen: (value: boolean) => void;
|
setIsSettingsOpen: (value: boolean) => void;
|
||||||
setIsEditModalOpen: (value: boolean) => void;
|
setIsEditModalOpen: (value: boolean) => void;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Space } from 'antd';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const RowContainer = styled.div`
|
export const RowContainer = styled.div`
|
||||||
@ -5,3 +6,9 @@ export const RowContainer = styled.div`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const RowSpace = styled(Space)`
|
||||||
|
&&& {
|
||||||
|
row-gap: 1.5rem !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
import { InfoCircleFilled } from '@ant-design/icons';
|
||||||
|
import { Card, Form, Input, Space, Typography } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
function EditGoogleAuth(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Typography.Paragraph>
|
||||||
|
Enter OAuth 2.0 credentials obtained from the Google API Console below. Read
|
||||||
|
the <a href="signoz.io/docs/userguide/sso-authentication">docs</a> for more
|
||||||
|
information.
|
||||||
|
</Typography.Paragraph>
|
||||||
|
<Form.Item
|
||||||
|
label="Client ID"
|
||||||
|
name={['googleAuthConfig', 'clientId']}
|
||||||
|
rules={[{ required: true, message: 'Please input Google Auth Client ID!' }]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="Client Secret"
|
||||||
|
name={['googleAuthConfig', 'clientSecret']}
|
||||||
|
rules={[
|
||||||
|
{ required: true, message: 'Please input Google Auth Client Secret!' },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Card style={{ marginBottom: '1rem' }}>
|
||||||
|
<Space>
|
||||||
|
<InfoCircleFilled />
|
||||||
|
<Typography>
|
||||||
|
Google OAuth2 won’t be enabled unless you enter all the attributes above
|
||||||
|
</Typography>
|
||||||
|
</Space>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EditGoogleAuth;
|
@ -0,0 +1,44 @@
|
|||||||
|
import { InfoCircleFilled } from '@ant-design/icons';
|
||||||
|
import { Card, Form, Input, Space, Typography } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
function EditSAML(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Form.Item
|
||||||
|
label="SAML ACS URL"
|
||||||
|
name={['samlConfig', 'samlIdp']}
|
||||||
|
rules={[{ required: true, message: 'Please input your ACS URL!' }]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="SAML Entity ID"
|
||||||
|
name={['samlConfig', 'samlEntity']}
|
||||||
|
rules={[{ required: true, message: 'Please input your Entity Id!' }]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
rules={[{ required: true, message: 'Please input your Certificate!' }]}
|
||||||
|
label="SAML X.509 Certificate"
|
||||||
|
name={['samlConfig', 'samlCert']}
|
||||||
|
>
|
||||||
|
<Input.TextArea rows={4} />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Card style={{ marginBottom: '1rem' }}>
|
||||||
|
<Space>
|
||||||
|
<InfoCircleFilled />
|
||||||
|
<Typography>
|
||||||
|
SAML won’t be enabled unless you enter all the attributes above
|
||||||
|
</Typography>
|
||||||
|
</Space>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EditSAML;
|
@ -0,0 +1,40 @@
|
|||||||
|
import {
|
||||||
|
AuthDomain,
|
||||||
|
GOOGLE_AUTH,
|
||||||
|
GoogleAuthConfig,
|
||||||
|
isGoogleAuthConfig,
|
||||||
|
isSAMLConfig,
|
||||||
|
SAML,
|
||||||
|
SAMLConfig,
|
||||||
|
} from 'types/api/SAML/listDomain';
|
||||||
|
|
||||||
|
export function parseSamlForm(
|
||||||
|
current: AuthDomain,
|
||||||
|
formValues: AuthDomain,
|
||||||
|
): SAMLConfig | undefined {
|
||||||
|
if (current?.ssoType === SAML && isSAMLConfig(formValues?.samlConfig)) {
|
||||||
|
return {
|
||||||
|
...current.samlConfig,
|
||||||
|
...formValues?.samlConfig,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return current.samlConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseGoogleAuthForm(
|
||||||
|
current: AuthDomain,
|
||||||
|
formValues: AuthDomain,
|
||||||
|
): GoogleAuthConfig | undefined {
|
||||||
|
if (
|
||||||
|
current?.ssoType === GOOGLE_AUTH &&
|
||||||
|
isGoogleAuthConfig(formValues?.googleAuthConfig)
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
...current.googleAuthConfig,
|
||||||
|
...formValues?.googleAuthConfig,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return current.googleAuthConfig;
|
||||||
|
}
|
@ -1,27 +1,33 @@
|
|||||||
import { InfoCircleFilled } from '@ant-design/icons';
|
import { Button, Form, notification, Space } from 'antd';
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Card,
|
|
||||||
Form,
|
|
||||||
Input,
|
|
||||||
notification,
|
|
||||||
Space,
|
|
||||||
Typography,
|
|
||||||
} from 'antd';
|
|
||||||
import { useForm } from 'antd/lib/form/Form';
|
import { useForm } from 'antd/lib/form/Form';
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { SAMLDomain } from 'types/api/SAML/listDomain';
|
import { AuthDomain, GOOGLE_AUTH, SAML } from 'types/api/SAML/listDomain';
|
||||||
|
|
||||||
function EditSaml({
|
import EditGoogleAuth from './EditGoogleAuth';
|
||||||
certificate,
|
import EditSAML from './EditSAML';
|
||||||
entityId,
|
import { parseGoogleAuthForm, parseSamlForm } from './helpers';
|
||||||
url,
|
|
||||||
|
// renderFormInputs selectively renders form fields depending upon
|
||||||
|
// sso type
|
||||||
|
const renderFormInputs = (
|
||||||
|
record: AuthDomain | undefined,
|
||||||
|
): JSX.Element | undefined => {
|
||||||
|
switch (record?.ssoType) {
|
||||||
|
case GOOGLE_AUTH:
|
||||||
|
return <EditGoogleAuth />;
|
||||||
|
case SAML:
|
||||||
|
default:
|
||||||
|
return <EditSAML />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function EditSSO({
|
||||||
onRecordUpdateHandler,
|
onRecordUpdateHandler,
|
||||||
record,
|
record,
|
||||||
setEditModalOpen,
|
setEditModalOpen,
|
||||||
}: EditFormProps): JSX.Element {
|
}: EditFormProps): JSX.Element {
|
||||||
const [form] = useForm<EditFormProps>();
|
const [form] = useForm<AuthDomain>();
|
||||||
|
|
||||||
const { t } = useTranslation(['common']);
|
const { t } = useTranslation(['common']);
|
||||||
|
|
||||||
@ -32,12 +38,9 @@ function EditSaml({
|
|||||||
await onRecordUpdateHandler({
|
await onRecordUpdateHandler({
|
||||||
...record,
|
...record,
|
||||||
ssoEnabled: true,
|
ssoEnabled: true,
|
||||||
samlConfig: {
|
ssoType: record.ssoType,
|
||||||
...record.samlConfig,
|
samlConfig: parseSamlForm(record, values),
|
||||||
samlCert: values.certificate,
|
googleAuthConfig: parseGoogleAuthForm(record, values),
|
||||||
samlEntity: values.entityId,
|
|
||||||
samlIdp: values.url,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
@ -55,7 +58,7 @@ function EditSaml({
|
|||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
name="basic"
|
name="basic"
|
||||||
initialValues={{ certificate, entityId, url }}
|
initialValues={record}
|
||||||
onFinishFailed={(error): void => {
|
onFinishFailed={(error): void => {
|
||||||
error.errorFields.forEach(({ errors }) => {
|
error.errorFields.forEach(({ errors }) => {
|
||||||
notification.error({
|
notification.error({
|
||||||
@ -70,39 +73,7 @@ function EditSaml({
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
form={form}
|
form={form}
|
||||||
>
|
>
|
||||||
<Form.Item
|
{renderFormInputs(record)}
|
||||||
label="SAML ACS URL"
|
|
||||||
name="url"
|
|
||||||
rules={[{ required: true, message: 'Please input your ACS URL!' }]}
|
|
||||||
>
|
|
||||||
<Input />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label="SAML Entity ID"
|
|
||||||
name="entityId"
|
|
||||||
rules={[{ required: true, message: 'Please input your Entity Id!' }]}
|
|
||||||
>
|
|
||||||
<Input />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
rules={[{ required: true, message: 'Please input your Certificate!' }]}
|
|
||||||
label="SAML X.509 Certificate"
|
|
||||||
name="certificate"
|
|
||||||
>
|
|
||||||
<Input.TextArea rows={4} />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Card style={{ marginBottom: '1rem' }}>
|
|
||||||
<Space>
|
|
||||||
<InfoCircleFilled />
|
|
||||||
<Typography>
|
|
||||||
SAML won’t be enabled unless you enter all the attributes above
|
|
||||||
</Typography>
|
|
||||||
</Space>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
style={{ width: '100%', justifyContent: 'flex-end' }}
|
style={{ width: '100%', justifyContent: 'flex-end' }}
|
||||||
align="end"
|
align="end"
|
||||||
@ -120,12 +91,9 @@ function EditSaml({
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface EditFormProps {
|
interface EditFormProps {
|
||||||
url: string;
|
onRecordUpdateHandler: (record: AuthDomain) => Promise<boolean>;
|
||||||
entityId: string;
|
record: AuthDomain;
|
||||||
certificate: string;
|
|
||||||
onRecordUpdateHandler: (record: SAMLDomain) => Promise<boolean>;
|
|
||||||
record: SAMLDomain;
|
|
||||||
setEditModalOpen: (open: boolean) => void;
|
setEditModalOpen: (open: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default EditSaml;
|
export default EditSSO;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { Switch } from 'antd';
|
import { Switch } from 'antd';
|
||||||
import React, { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { SAMLDomain } from 'types/api/SAML/listDomain';
|
import { AuthDomain } from 'types/api/SAML/listDomain';
|
||||||
|
|
||||||
import { getIsValidCertificate } from '../utils';
|
import { isSSOConfigValid } from '../helpers';
|
||||||
|
|
||||||
function SwitchComponent({
|
function SwitchComponent({
|
||||||
isDefaultChecked,
|
isDefaultChecked,
|
||||||
@ -25,10 +25,7 @@ function SwitchComponent({
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isInValidVerificate = useMemo(
|
const isInValidVerificate = useMemo(() => !isSSOConfigValid(record), [record]);
|
||||||
() => !getIsValidCertificate(record?.samlConfig),
|
|
||||||
[record],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Switch
|
<Switch
|
||||||
@ -42,8 +39,8 @@ function SwitchComponent({
|
|||||||
|
|
||||||
interface SwitchComponentProps {
|
interface SwitchComponentProps {
|
||||||
isDefaultChecked: boolean;
|
isDefaultChecked: boolean;
|
||||||
onRecordUpdateHandler: (record: SAMLDomain) => Promise<boolean>;
|
onRecordUpdateHandler: (record: AuthDomain) => Promise<boolean>;
|
||||||
record: SAMLDomain;
|
record: AuthDomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SwitchComponent;
|
export default SwitchComponent;
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
import { AuthDomain, SAML } from 'types/api/SAML/listDomain';
|
||||||
|
|
||||||
|
import { isSSOConfigValid } from './helpers';
|
||||||
|
|
||||||
|
const inValidCase: AuthDomain['samlConfig'][] = [
|
||||||
|
{
|
||||||
|
samlCert: '',
|
||||||
|
samlEntity: '',
|
||||||
|
samlIdp: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
samlCert: '',
|
||||||
|
samlEntity: '',
|
||||||
|
samlIdp: 'asd',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
samlCert: 'sample certificate',
|
||||||
|
samlEntity: '',
|
||||||
|
samlIdp: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
samlCert: 'sample cert',
|
||||||
|
samlEntity: 'sample entity',
|
||||||
|
samlIdp: '',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const validCase: AuthDomain['samlConfig'][] = [
|
||||||
|
{
|
||||||
|
samlCert: 'sample cert',
|
||||||
|
samlEntity: 'sample entity',
|
||||||
|
samlIdp: 'sample idp',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('Utils', () => {
|
||||||
|
inValidCase.forEach((config) => {
|
||||||
|
it('should return invalid saml config', () => {
|
||||||
|
expect(
|
||||||
|
isSSOConfigValid({
|
||||||
|
id: 'test-0',
|
||||||
|
name: 'test',
|
||||||
|
orgId: '32ed234',
|
||||||
|
ssoEnabled: true,
|
||||||
|
ssoType: SAML,
|
||||||
|
samlConfig: {
|
||||||
|
samlCert: config?.samlCert || '',
|
||||||
|
samlEntity: config?.samlEntity || '',
|
||||||
|
samlIdp: config?.samlIdp || '',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
validCase.forEach((config) => {
|
||||||
|
it('should return invalid saml config', () => {
|
||||||
|
expect(
|
||||||
|
isSSOConfigValid({
|
||||||
|
id: 'test-0',
|
||||||
|
name: 'test',
|
||||||
|
orgId: '32ed234',
|
||||||
|
ssoEnabled: true,
|
||||||
|
ssoType: SAML,
|
||||||
|
samlConfig: {
|
||||||
|
samlCert: config?.samlCert || '',
|
||||||
|
samlEntity: config?.samlEntity || '',
|
||||||
|
samlIdp: config?.samlIdp || '',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,45 @@
|
|||||||
|
import { AuthDomain, GOOGLE_AUTH, SAML } from 'types/api/SAML/listDomain';
|
||||||
|
|
||||||
|
export const ConfigureSsoButtonText = (
|
||||||
|
ssoType: AuthDomain['ssoType'],
|
||||||
|
): string => {
|
||||||
|
switch (ssoType) {
|
||||||
|
case SAML:
|
||||||
|
return 'Edit SAML';
|
||||||
|
case GOOGLE_AUTH:
|
||||||
|
return 'Edit Google Auth';
|
||||||
|
default:
|
||||||
|
return 'Configure SSO';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const EditModalTitleText = (
|
||||||
|
ssoType: AuthDomain['ssoType'] | undefined,
|
||||||
|
): string => {
|
||||||
|
switch (ssoType) {
|
||||||
|
case SAML:
|
||||||
|
return 'Edit SAML Configuration';
|
||||||
|
case GOOGLE_AUTH:
|
||||||
|
return 'Edit Google Authentication';
|
||||||
|
default:
|
||||||
|
return 'Configure SSO';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isSSOConfigValid = (domain: AuthDomain): boolean => {
|
||||||
|
switch (domain.ssoType) {
|
||||||
|
case SAML:
|
||||||
|
return (
|
||||||
|
domain.samlConfig?.samlCert?.length !== 0 &&
|
||||||
|
domain.samlConfig?.samlEntity?.length !== 0 &&
|
||||||
|
domain.samlConfig?.samlIdp?.length !== 0
|
||||||
|
);
|
||||||
|
case GOOGLE_AUTH:
|
||||||
|
return (
|
||||||
|
domain.googleAuthConfig?.clientId?.length !== 0 &&
|
||||||
|
domain.googleAuthConfig?.clientSecret?.length !== 0
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
@ -1,9 +1,10 @@
|
|||||||
import { LockTwoTone } from '@ant-design/icons';
|
import { LockTwoTone } from '@ant-design/icons';
|
||||||
import { Button, Modal, notification, Space, Table } from 'antd';
|
import { Button, Modal, notification, Space, Table, Typography } from 'antd';
|
||||||
import { ColumnsType } from 'antd/lib/table';
|
import { ColumnsType } from 'antd/lib/table';
|
||||||
import deleteDomain from 'api/SAML/deleteDomain';
|
import deleteDomain from 'api/SAML/deleteDomain';
|
||||||
import listAllDomain from 'api/SAML/listAllDomain';
|
import listAllDomain from 'api/SAML/listAllDomain';
|
||||||
import updateDomain from 'api/SAML/updateDomain';
|
import updateDomain from 'api/SAML/updateDomain';
|
||||||
|
import TextToolTip from 'components/TextToolTip';
|
||||||
import { SIGNOZ_UPGRADE_PLAN_URL } from 'constants/app';
|
import { SIGNOZ_UPGRADE_PLAN_URL } from 'constants/app';
|
||||||
import { FeatureKeys } from 'constants/featureKeys';
|
import { FeatureKeys } from 'constants/featureKeys';
|
||||||
import useFeatureFlag from 'hooks/useFeatureFlag';
|
import useFeatureFlag from 'hooks/useFeatureFlag';
|
||||||
@ -12,25 +13,27 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { SAMLDomain } from 'types/api/SAML/listDomain';
|
import { AuthDomain } from 'types/api/SAML/listDomain';
|
||||||
import AppReducer from 'types/reducer/app';
|
import AppReducer from 'types/reducer/app';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
import AddDomain from './AddDomain';
|
import AddDomain from './AddDomain';
|
||||||
import Create from './Create';
|
import Create from './Create';
|
||||||
import EditSaml from './Edit';
|
import EditSSO from './Edit';
|
||||||
|
import { ConfigureSsoButtonText, EditModalTitleText } from './helpers';
|
||||||
|
import { ColumnWithTooltip } from './styles';
|
||||||
import SwitchComponent from './Switch';
|
import SwitchComponent from './Switch';
|
||||||
|
|
||||||
function AuthDomains(): JSX.Element {
|
function AuthDomains(): JSX.Element {
|
||||||
const { t } = useTranslation(['common', 'organizationsettings']);
|
const { t } = useTranslation(['common', 'organizationsettings']);
|
||||||
const [isSettingsOpen, setIsSettingsOpen] = useState<boolean>(false);
|
const [isSettingsOpen, setIsSettingsOpen] = useState<boolean>(false);
|
||||||
const { org } = useSelector<AppState, AppReducer>((state) => state.app);
|
const { org } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||||
const [currentDomain, setCurrentDomain] = useState<SAMLDomain>();
|
const [currentDomain, setCurrentDomain] = useState<AuthDomain>();
|
||||||
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
|
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
|
||||||
|
|
||||||
const SSOFlag = useFeatureFlag(FeatureKeys.SSO);
|
const SSOFlag = useFeatureFlag(FeatureKeys.SSO);
|
||||||
|
|
||||||
const notEntripriseData: SAMLDomain[] = [
|
const notEntripriseData: AuthDomain[] = [
|
||||||
{
|
{
|
||||||
id: v4(),
|
id: v4(),
|
||||||
name: '',
|
name: '',
|
||||||
@ -53,6 +56,13 @@ function AuthDomains(): JSX.Element {
|
|||||||
enabled: org !== null,
|
enabled: org !== null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const assignSsoMethod = useCallback(
|
||||||
|
(typ: AuthDomain['ssoType']): void => {
|
||||||
|
setCurrentDomain({ ...currentDomain, ssoType: typ } as AuthDomain);
|
||||||
|
},
|
||||||
|
[currentDomain, setCurrentDomain],
|
||||||
|
);
|
||||||
|
|
||||||
const onCloseHandler = useCallback(
|
const onCloseHandler = useCallback(
|
||||||
(func: React.Dispatch<React.SetStateAction<boolean>>) => (): void => {
|
(func: React.Dispatch<React.SetStateAction<boolean>>) => (): void => {
|
||||||
func(false);
|
func(false);
|
||||||
@ -61,7 +71,7 @@ function AuthDomains(): JSX.Element {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const onRecordUpdateHandler = useCallback(
|
const onRecordUpdateHandler = useCallback(
|
||||||
async (record: SAMLDomain): Promise<boolean> => {
|
async (record: AuthDomain): Promise<boolean> => {
|
||||||
try {
|
try {
|
||||||
const response = await updateDomain(record);
|
const response = await updateDomain(record);
|
||||||
|
|
||||||
@ -104,15 +114,20 @@ function AuthDomains(): JSX.Element {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const onEditHandler = useCallback(
|
const onEditHandler = useCallback(
|
||||||
(record: SAMLDomain) => (): void => {
|
(record: AuthDomain) => (): void => {
|
||||||
onOpenHandler(setIsEditModalOpen)();
|
if (!record.ssoType) {
|
||||||
|
onOpenHandler(setIsSettingsOpen)();
|
||||||
|
} else {
|
||||||
|
onOpenHandler(setIsEditModalOpen)();
|
||||||
|
}
|
||||||
|
|
||||||
setCurrentDomain(record);
|
setCurrentDomain(record);
|
||||||
},
|
},
|
||||||
[onOpenHandler],
|
[onOpenHandler],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onDeleteHandler = useCallback(
|
const onDeleteHandler = useCallback(
|
||||||
(record: SAMLDomain) => (): void => {
|
(record: AuthDomain) => (): void => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
centered: true,
|
centered: true,
|
||||||
title: t('delete_domain', {
|
title: t('delete_domain', {
|
||||||
@ -146,17 +161,27 @@ function AuthDomains(): JSX.Element {
|
|||||||
window.open(SIGNOZ_UPGRADE_PLAN_URL);
|
window.open(SIGNOZ_UPGRADE_PLAN_URL);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const columns: ColumnsType<SAMLDomain> = [
|
const columns: ColumnsType<AuthDomain> = [
|
||||||
{
|
{
|
||||||
title: 'Domain',
|
title: 'Domain',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
key: 'name',
|
key: 'name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Enforce SSO',
|
title: (
|
||||||
|
<ColumnWithTooltip>
|
||||||
|
<Typography>Enforce SSO</Typography>
|
||||||
|
<TextToolTip
|
||||||
|
{...{
|
||||||
|
text: `When enabled, this option restricts users to SSO based authentication. For more information, click `,
|
||||||
|
url: 'https://signoz.io/docs/userguide/sso-authentication/',
|
||||||
|
}}
|
||||||
|
/>{' '}
|
||||||
|
</ColumnWithTooltip>
|
||||||
|
),
|
||||||
dataIndex: 'ssoEnabled',
|
dataIndex: 'ssoEnabled',
|
||||||
key: 'ssoEnabled',
|
key: 'ssoEnabled',
|
||||||
render: (value: boolean, record: SAMLDomain): JSX.Element => {
|
render: (value: boolean, record: AuthDomain): JSX.Element => {
|
||||||
if (!SSOFlag) {
|
if (!SSOFlag) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
@ -182,7 +207,7 @@ function AuthDomains(): JSX.Element {
|
|||||||
title: '',
|
title: '',
|
||||||
dataIndex: 'description',
|
dataIndex: 'description',
|
||||||
key: 'description',
|
key: 'description',
|
||||||
render: (_, record: SAMLDomain): JSX.Element => {
|
render: (_, record: AuthDomain): JSX.Element => {
|
||||||
if (!SSOFlag) {
|
if (!SSOFlag) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
@ -197,7 +222,7 @@ function AuthDomains(): JSX.Element {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Button type="link" onClick={onEditHandler(record)}>
|
<Button type="link" onClick={onEditHandler(record)}>
|
||||||
Edit SSO
|
{ConfigureSsoButtonText(record.ssoType)}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -235,12 +260,14 @@ function AuthDomains(): JSX.Element {
|
|||||||
footer={null}
|
footer={null}
|
||||||
>
|
>
|
||||||
<Create
|
<Create
|
||||||
|
ssoMethod={currentDomain?.ssoType as AuthDomain['ssoType']}
|
||||||
|
assignSsoMethod={assignSsoMethod}
|
||||||
setIsEditModalOpen={setIsEditModalOpen}
|
setIsEditModalOpen={setIsEditModalOpen}
|
||||||
setIsSettingsOpen={setIsSettingsOpen}
|
setIsSettingsOpen={setIsSettingsOpen}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
<Table
|
<Table
|
||||||
rowKey={(record: SAMLDomain): string => record.name + v4()}
|
rowKey={(record: AuthDomain): string => record.name + v4()}
|
||||||
dataSource={!SSOFlag ? notEntripriseData : []}
|
dataSource={!SSOFlag ? notEntripriseData : []}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
tableLayout="fixed"
|
tableLayout="fixed"
|
||||||
@ -262,6 +289,8 @@ function AuthDomains(): JSX.Element {
|
|||||||
footer={null}
|
footer={null}
|
||||||
>
|
>
|
||||||
<Create
|
<Create
|
||||||
|
ssoMethod={currentDomain?.ssoType as AuthDomain['ssoType']}
|
||||||
|
assignSsoMethod={assignSsoMethod}
|
||||||
setIsSettingsOpen={setIsSettingsOpen}
|
setIsSettingsOpen={setIsSettingsOpen}
|
||||||
setIsEditModalOpen={setIsEditModalOpen}
|
setIsEditModalOpen={setIsEditModalOpen}
|
||||||
/>
|
/>
|
||||||
@ -270,18 +299,15 @@ function AuthDomains(): JSX.Element {
|
|||||||
<Modal
|
<Modal
|
||||||
visible={isEditModalOpen}
|
visible={isEditModalOpen}
|
||||||
centered
|
centered
|
||||||
title="Configure SAML"
|
title={EditModalTitleText(currentDomain?.ssoType)}
|
||||||
onCancel={onCloseHandler(setIsEditModalOpen)}
|
onCancel={onCloseHandler(setIsEditModalOpen)}
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
style={{ minWidth: '600px' }}
|
style={{ minWidth: '600px' }}
|
||||||
footer={null}
|
footer={null}
|
||||||
>
|
>
|
||||||
<EditSaml
|
<EditSSO
|
||||||
certificate={currentDomain?.samlConfig?.samlCert || ''}
|
|
||||||
entityId={currentDomain?.samlConfig?.samlEntity || ''}
|
|
||||||
url={currentDomain?.samlConfig?.samlIdp || ''}
|
|
||||||
onRecordUpdateHandler={onRecordUpdateHandler}
|
onRecordUpdateHandler={onRecordUpdateHandler}
|
||||||
record={currentDomain as SAMLDomain}
|
record={currentDomain as AuthDomain}
|
||||||
setEditModalOpen={setIsEditModalOpen}
|
setEditModalOpen={setIsEditModalOpen}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
@ -294,7 +320,7 @@ function AuthDomains(): JSX.Element {
|
|||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
tableLayout="fixed"
|
tableLayout="fixed"
|
||||||
rowKey={(record: SAMLDomain): string => record.name + v4()}
|
rowKey={(record: AuthDomain): string => record.name + v4()}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</>
|
</>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Row } from 'antd';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const Container = styled.div`
|
export const Container = styled.div`
|
||||||
@ -5,3 +6,9 @@ export const Container = styled.div`
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const ColumnWithTooltip = styled(Row)`
|
||||||
|
&&& > article {
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
import { SAMLDomain } from 'types/api/SAML/listDomain';
|
|
||||||
|
|
||||||
import { getIsValidCertificate } from './utils';
|
|
||||||
|
|
||||||
const inValidCase: SAMLDomain['samlConfig'][] = [
|
|
||||||
{
|
|
||||||
samlCert: '',
|
|
||||||
samlEntity: '',
|
|
||||||
samlIdp: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
samlCert: '',
|
|
||||||
samlEntity: '',
|
|
||||||
samlIdp: 'asd',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
samlCert: 'sample certificate',
|
|
||||||
samlEntity: '',
|
|
||||||
samlIdp: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
samlCert: 'sample cert',
|
|
||||||
samlEntity: 'sample entity',
|
|
||||||
samlIdp: '',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const validCase: SAMLDomain['samlConfig'][] = [
|
|
||||||
{
|
|
||||||
samlCert: 'sample cert',
|
|
||||||
samlEntity: 'sample entity',
|
|
||||||
samlIdp: 'sample idp',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
describe('Utils', () => {
|
|
||||||
inValidCase.forEach((config) => {
|
|
||||||
it('should return invalid saml config', () => {
|
|
||||||
expect(
|
|
||||||
getIsValidCertificate({
|
|
||||||
samlCert: config.samlCert,
|
|
||||||
samlEntity: config.samlEntity,
|
|
||||||
samlIdp: config.samlIdp,
|
|
||||||
}),
|
|
||||||
).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
validCase.forEach((config) => {
|
|
||||||
it('should return invalid saml config', () => {
|
|
||||||
expect(
|
|
||||||
getIsValidCertificate({
|
|
||||||
samlCert: config.samlCert,
|
|
||||||
samlEntity: config.samlEntity,
|
|
||||||
samlIdp: config.samlIdp,
|
|
||||||
}),
|
|
||||||
).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,13 +0,0 @@
|
|||||||
import { SAMLConfig } from 'types/api/SAML/listDomain';
|
|
||||||
|
|
||||||
export const getIsValidCertificate = (config: SAMLConfig): boolean => {
|
|
||||||
if (config === null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
config?.samlCert?.length !== 0 &&
|
|
||||||
config?.samlEntity?.length !== 0 &&
|
|
||||||
config?.samlIdp?.length !== 0
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,5 +1,5 @@
|
|||||||
import { SAMLDomain } from './listDomain';
|
import { AuthDomain } from './listDomain';
|
||||||
|
|
||||||
export type Props = SAMLDomain;
|
export type Props = AuthDomain;
|
||||||
|
|
||||||
export type PayloadProps = SAMLDomain;
|
export type PayloadProps = AuthDomain;
|
||||||
|
@ -6,17 +6,42 @@ export interface SAMLConfig {
|
|||||||
samlCert: string;
|
samlCert: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SAMLDomain {
|
export function isSAMLConfig(
|
||||||
|
value: SAMLConfig | undefined,
|
||||||
|
): value is SAMLConfig {
|
||||||
|
return (
|
||||||
|
value?.samlEntity !== undefined ||
|
||||||
|
value?.samlIdp !== undefined ||
|
||||||
|
value?.samlCert !== undefined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GoogleAuthConfig {
|
||||||
|
clientId: string;
|
||||||
|
clientSecret: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isGoogleAuthConfig(
|
||||||
|
value: GoogleAuthConfig | undefined,
|
||||||
|
): value is GoogleAuthConfig {
|
||||||
|
return value?.clientId !== undefined || value?.clientSecret !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SAML = 'SAML';
|
||||||
|
export const GOOGLE_AUTH = 'GOOGLE_AUTH';
|
||||||
|
|
||||||
|
export interface AuthDomain {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
orgId: Organization['id'];
|
orgId: Organization['id'];
|
||||||
ssoEnabled: boolean;
|
ssoEnabled: boolean;
|
||||||
ssoType: 'SAML';
|
ssoType: 'SAML' | 'GOOGLE_AUTH';
|
||||||
samlConfig: SAMLConfig;
|
samlConfig?: SAMLConfig;
|
||||||
|
googleAuthConfig?: GoogleAuthConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
orgId: Organization['id'];
|
orgId: Organization['id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PayloadProps = SAMLDomain[];
|
export type PayloadProps = AuthDomain[];
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { SAMLDomain } from './listDomain';
|
import { AuthDomain } from './listDomain';
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
name: string;
|
name: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PayloadProps = SAMLDomain;
|
export type PayloadProps = AuthDomain;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { SAMLDomain } from './listDomain';
|
import { AuthDomain } from './listDomain';
|
||||||
|
|
||||||
export type Props = SAMLDomain;
|
export type Props = AuthDomain;
|
||||||
|
|
||||||
export type PayloadProps = SAMLDomain;
|
export type PayloadProps = AuthDomain;
|
||||||
|
26
go.mod
26
go.mod
@ -5,6 +5,7 @@ go 1.17
|
|||||||
require (
|
require (
|
||||||
github.com/ClickHouse/clickhouse-go/v2 v2.0.12
|
github.com/ClickHouse/clickhouse-go/v2 v2.0.12
|
||||||
github.com/SigNoz/govaluate v0.0.0-20220522085550-d19c08c206cb
|
github.com/SigNoz/govaluate v0.0.0-20220522085550-d19c08c206cb
|
||||||
|
github.com/coreos/go-oidc/v3 v3.4.0
|
||||||
github.com/go-kit/log v0.1.0
|
github.com/go-kit/log v0.1.0
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/gorilla/handlers v1.5.1
|
github.com/gorilla/handlers v1.5.1
|
||||||
@ -33,9 +34,10 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
cloud.google.com/go/compute v1.7.0 // indirect
|
||||||
github.com/beevik/etree v1.1.0 // indirect
|
github.com/beevik/etree v1.1.0 // indirect
|
||||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect
|
github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect
|
||||||
github.com/google/go-cmp v0.5.8 // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa // indirect
|
||||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/klauspost/cpuid v1.2.3 // indirect
|
github.com/klauspost/cpuid v1.2.3 // indirect
|
||||||
@ -46,11 +48,11 @@ require (
|
|||||||
github.com/prometheus/client_golang v0.9.0-pre1.0.20181001174001-0a8115f42e03 // indirect
|
github.com/prometheus/client_golang v0.9.0-pre1.0.20181001174001-0a8115f42e03 // indirect
|
||||||
github.com/prometheus/tsdb v0.0.0-20181003080831-0ce41118ed20 // indirect
|
github.com/prometheus/tsdb v0.0.0-20181003080831-0ce41118ed20 // indirect
|
||||||
gopkg.in/ini.v1 v1.42.0 // indirect
|
gopkg.in/ini.v1 v1.42.0 // indirect
|
||||||
|
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go v0.88.0 // indirect
|
|
||||||
github.com/Azure/azure-sdk-for-go v5.0.0-beta.0.20161028183111-bd73d950fa44+incompatible // indirect
|
github.com/Azure/azure-sdk-for-go v5.0.0-beta.0.20161028183111-bd73d950fa44+incompatible // indirect
|
||||||
github.com/Azure/go-autorest v10.8.1+incompatible // indirect
|
github.com/Azure/go-autorest v10.8.1+incompatible // indirect
|
||||||
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||||
@ -76,7 +78,7 @@ require (
|
|||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/btree v1.0.0 // indirect
|
github.com/google/btree v1.0.0 // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
|
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
|
||||||
github.com/googleapis/gnostic v0.2.3-0.20180520015035-48a0ecefe2e4 // indirect
|
github.com/googleapis/gnostic v0.2.3-0.20180520015035-48a0ecefe2e4 // indirect
|
||||||
github.com/gophercloud/gophercloud v0.0.0-20170607034829-caf34a65f602 // indirect
|
github.com/gophercloud/gophercloud v0.0.0-20170607034829-caf34a65f602 // indirect
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect
|
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect
|
||||||
@ -129,19 +131,19 @@ require (
|
|||||||
go.uber.org/atomic v1.6.0 // indirect
|
go.uber.org/atomic v1.6.0 // indirect
|
||||||
go.uber.org/multierr v1.5.0 // indirect
|
go.uber.org/multierr v1.5.0 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
|
||||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f
|
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b
|
||||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 // indirect
|
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
|
||||||
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08 // indirect
|
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
|
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
|
||||||
google.golang.org/api v0.51.0 // indirect
|
google.golang.org/api v0.84.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20211013025323-ce878158c4d4 // indirect
|
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90 // indirect
|
||||||
google.golang.org/grpc v1.41.0
|
google.golang.org/grpc v1.47.0
|
||||||
google.golang.org/grpc/examples v0.0.0-20210803221256-6ba56c814be7 // indirect
|
google.golang.org/grpc/examples v0.0.0-20210803221256-6ba56c814be7 // indirect
|
||||||
google.golang.org/protobuf v1.27.1 // indirect
|
google.golang.org/protobuf v1.28.0 // indirect
|
||||||
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
|
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
|
154
go.sum
154
go.sum
@ -21,16 +21,30 @@ cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E
|
|||||||
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
|
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
|
||||||
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
|
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
|
||||||
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
|
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
|
||||||
cloud.google.com/go v0.88.0 h1:MZ2cf9Elnv1wqccq8ooKO2MqHQLc+ChCp/+QWObCpxg=
|
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
|
||||||
cloud.google.com/go v0.88.0/go.mod h1:dnKwfYbP9hQhefiUvpbcAyoGSHUrOxR20JVElLiUvEY=
|
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
|
||||||
|
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
|
||||||
|
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
|
||||||
|
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
|
||||||
|
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
|
||||||
|
cloud.google.com/go v0.102.0 h1:DAq3r8y4mDgyB/ZPJ9v/5VJNqjgJAxTn6ZYLlUywOu8=
|
||||||
|
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
|
||||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||||
|
cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
|
||||||
|
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
|
||||||
|
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
|
||||||
|
cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
|
||||||
|
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
|
||||||
|
cloud.google.com/go/compute v1.7.0 h1:v/k9Eueb8aAJ0vZuxKMrgm6kPhCLZU9HxFU+AFDs9Uk=
|
||||||
|
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
|
||||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||||
|
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
|
||||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||||
@ -40,6 +54,7 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
|
|||||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||||
|
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
github.com/Azure/azure-sdk-for-go v5.0.0-beta.0.20161028183111-bd73d950fa44+incompatible h1:+5hx+ZckahrubYyxbjTwnq9w5xpnq1CwSL4N54I8/qc=
|
github.com/Azure/azure-sdk-for-go v5.0.0-beta.0.20161028183111-bd73d950fa44+incompatible h1:+5hx+ZckahrubYyxbjTwnq9w5xpnq1CwSL4N54I8/qc=
|
||||||
github.com/Azure/azure-sdk-for-go v5.0.0-beta.0.20161028183111-bd73d950fa44+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
github.com/Azure/azure-sdk-for-go v5.0.0-beta.0.20161028183111-bd73d950fa44+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||||
@ -91,10 +106,16 @@ github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h
|
|||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
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=
|
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cockroachdb/cmux v0.0.0-20170110192607-30d10be49292/go.mod h1:qRiX68mZX1lGBkTWyp3CLcenw9I94W2dLeRvMzcn9N4=
|
github.com/cockroachdb/cmux v0.0.0-20170110192607-30d10be49292/go.mod h1:qRiX68mZX1lGBkTWyp3CLcenw9I94W2dLeRvMzcn9N4=
|
||||||
github.com/cockroachdb/cockroach v0.0.0-20170608034007-84bc9597164f/go.mod h1:xeT/CQ0qZHangbYbWShlCGAx31aV4AjGswDUjhKS6HQ=
|
github.com/cockroachdb/cockroach v0.0.0-20170608034007-84bc9597164f/go.mod h1:xeT/CQ0qZHangbYbWShlCGAx31aV4AjGswDUjhKS6HQ=
|
||||||
|
github.com/coreos/go-oidc/v3 v3.4.0 h1:xz7elHb/LDwm/ERpwHd+5nb7wFHL32rsr6bBOgaeu6g=
|
||||||
|
github.com/coreos/go-oidc/v3 v3.4.0/go.mod h1:eHUXhZtXPQLgEaDrOVTgwbgmz1xGOkJNye6h3zkD2Pw=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@ -113,6 +134,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
|
|||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
|
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
|
||||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
@ -225,16 +247,24 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe
|
|||||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/pprof v0.0.0-20210715191844-86eeefc3e471/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa h1:7MYGT2XEMam7Mtzv1yDUYXANedWvwk3HKkR3MyGowy8=
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.4.0 h1:dS9eYAjhrE2RjmzYw2XAPvcXfmcQLtFEQWn0CR82awk=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
|
||||||
github.com/googleapis/gnostic v0.2.3-0.20180520015035-48a0ecefe2e4 h1:Z09Qt6AGDtg0cC/YgnX/iymzIqmZf5aasP5JZFxmkNQ=
|
github.com/googleapis/gnostic v0.2.3-0.20180520015035-48a0ecefe2e4 h1:Z09Qt6AGDtg0cC/YgnX/iymzIqmZf5aasP5JZFxmkNQ=
|
||||||
github.com/googleapis/gnostic v0.2.3-0.20180520015035-48a0ecefe2e4/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
github.com/googleapis/gnostic v0.2.3-0.20180520015035-48a0ecefe2e4/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||||
|
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
|
||||||
github.com/gophercloud/gophercloud v0.0.0-20170607034829-caf34a65f602 h1:Acc1d6mIuURCyYN6nkm1d7+Gycfq1+jUWdnBbTyGb6E=
|
github.com/gophercloud/gophercloud v0.0.0-20170607034829-caf34a65f602 h1:Acc1d6mIuURCyYN6nkm1d7+Gycfq1+jUWdnBbTyGb6E=
|
||||||
github.com/gophercloud/gophercloud v0.0.0-20170607034829-caf34a65f602/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4=
|
github.com/gophercloud/gophercloud v0.0.0-20170607034829-caf34a65f602/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
@ -572,8 +602,15 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY=
|
||||||
|
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@ -586,8 +623,16 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ
|
|||||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 h1:3B43BWw0xEBsLZ/NO1VALz6fppU3481pik+2Ksv45z8=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 h1:2o1E+E8TpNLklK9nHiPiK1uzIYrIHt+cQx3ynCwq9V8=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/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=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -598,8 +643,9 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
|
||||||
|
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -647,10 +693,27 @@ golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08 h1:WecRHqgE09JBkh/584XIE6PMz5KKE/vER4izNUi30AQ=
|
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
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-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-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=
|
||||||
|
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
|
||||||
|
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@ -728,8 +791,11 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||||
|
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||||
google.golang.org/api v0.0.0-20180506000402-20530fd5d65a/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
google.golang.org/api v0.0.0-20180506000402-20530fd5d65a/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
@ -755,8 +821,22 @@ google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk
|
|||||||
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
|
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
|
||||||
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
|
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
|
||||||
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
|
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
|
||||||
google.golang.org/api v0.51.0 h1:SQaA2Cx57B+iPw2MBgyjEkoeMkRK2IenSGoia0U3lCk=
|
|
||||||
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
|
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
|
||||||
|
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
|
||||||
|
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||||
|
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||||
|
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
|
||||||
|
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
|
||||||
|
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
|
||||||
|
google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
|
||||||
|
google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
|
||||||
|
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
|
||||||
|
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
|
||||||
|
google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
|
||||||
|
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
|
||||||
|
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
|
||||||
|
google.golang.org/api v0.84.0 h1:NMB9J4cCxs9xEm+1Z9QiO3eFvn7EnQj3Eo3hN6ugVlg=
|
||||||
|
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
@ -806,6 +886,7 @@ google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6D
|
|||||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||||
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
||||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||||
@ -814,9 +895,37 @@ google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxH
|
|||||||
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
||||||
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||||
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||||
google.golang.org/genproto v0.0.0-20210721163202-f1cecdd8b78a/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||||
google.golang.org/genproto v0.0.0-20211013025323-ce878158c4d4 h1:NBxB1XxiWpGqkPUiJ9PoBXkHV5A9+GohMOA+EmWoPbU=
|
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||||
google.golang.org/genproto v0.0.0-20211013025323-ce878158c4d4/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
|
||||||
|
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||||
|
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||||
|
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||||
|
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||||
|
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||||
|
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||||
|
google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||||
|
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||||
|
google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||||
|
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
|
||||||
|
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||||
|
google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||||
|
google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||||
|
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||||
|
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90 h1:4SPz2GL2CXJt28MTF8V6Ap/9ZiVbQlJeGSd9qtA7DLs=
|
||||||
|
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
@ -840,9 +949,15 @@ google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ
|
|||||||
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||||
|
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||||
google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E=
|
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||||
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||||
|
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||||
|
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||||
|
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||||
|
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
|
||||||
|
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||||
google.golang.org/grpc/examples v0.0.0-20210803221256-6ba56c814be7 h1:k3XsiLoPLXhNlZJy1sHKvkgGEfpMk8bsdJVHKKhTdrc=
|
google.golang.org/grpc/examples v0.0.0-20210803221256-6ba56c814be7 h1:k3XsiLoPLXhNlZJy1sHKvkgGEfpMk8bsdJVHKKhTdrc=
|
||||||
google.golang.org/grpc/examples v0.0.0-20210803221256-6ba56c814be7/go.mod h1:bF8wuZSAZTcbF7ZPKrDI/qY52toTP/yxLpRRY4Eu9Js=
|
google.golang.org/grpc/examples v0.0.0-20210803221256-6ba56c814be7/go.mod h1:bF8wuZSAZTcbF7ZPKrDI/qY52toTP/yxLpRRY4Eu9Js=
|
||||||
@ -858,8 +973,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
|||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
|
||||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||||
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.5/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.5/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
@ -875,6 +991,8 @@ gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
|
|||||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/segmentio/analytics-go.v3 v3.1.0 h1:UzxH1uaGZRpMKDhJyBz0pexz6yUoBU3x8bJsRk/HV6U=
|
gopkg.in/segmentio/analytics-go.v3 v3.1.0 h1:UzxH1uaGZRpMKDhJyBz0pexz6yUoBU3x8bJsRk/HV6U=
|
||||||
gopkg.in/segmentio/analytics-go.v3 v3.1.0/go.mod h1:4QqqlTlSSpVlWA9/9nDcPw+FkM2yv1NQoYjUbL9/JAw=
|
gopkg.in/segmentio/analytics-go.v3 v3.1.0/go.mod h1:4QqqlTlSSpVlWA9/9nDcPw+FkM2yv1NQoYjUbL9/JAw=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
Loading…
x
Reference in New Issue
Block a user