mirror of
https://github.com/nabbar/golib.git
synced 2025-10-25 08:40:34 +08:00
- Refactor context for ldap + dialer
- Add new package for context : * create a context based on gin.context struct * create a isolated context from parent context
This commit is contained in:
@@ -93,11 +93,11 @@ var _ = Describe("Role", func() {
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
It("Must return 1 policy", func() {
|
||||
var policies []*types.AttachedPolicy
|
||||
var policies []types.AttachedPolicy
|
||||
|
||||
if minioMode {
|
||||
err = nil
|
||||
policies = []*types.AttachedPolicy{
|
||||
policies = []types.AttachedPolicy{
|
||||
{
|
||||
PolicyArn: aws.String(policyArn),
|
||||
PolicyName: aws.String(name),
|
||||
@@ -162,11 +162,11 @@ var _ = Describe("Role", func() {
|
||||
})
|
||||
Context("List", func() {
|
||||
It("Must return 1 role", func() {
|
||||
var roles []*types.Role
|
||||
var roles []types.Role
|
||||
|
||||
if minioMode {
|
||||
err = nil
|
||||
roles = []*types.Role{
|
||||
roles = []types.Role{
|
||||
{
|
||||
Arn: aws.String(arn),
|
||||
RoleName: aws.String(name),
|
||||
|
||||
32
context/context.go
Normal file
32
context/context.go
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Nicolas JUHEL
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
package context
|
||||
|
||||
import "context"
|
||||
|
||||
func IsolateParent(parent context.Context) context.Context {
|
||||
x, _ := context.WithCancel(parent)
|
||||
return x
|
||||
}
|
||||
@@ -1 +1,85 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Nicolas JUHEL
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
package context
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type GinTonic interface {
|
||||
context.Context
|
||||
|
||||
//generic
|
||||
GinContext() *gin.Context
|
||||
|
||||
//gin context metadata
|
||||
Set(key string, value interface{})
|
||||
Get(key string) (value interface{}, exists bool)
|
||||
MustGet(key string) interface{}
|
||||
GetString(key string) (s string)
|
||||
GetBool(key string) (b bool)
|
||||
GetInt(key string) (i int)
|
||||
GetInt64(key string) (i64 int64)
|
||||
GetFloat64(key string) (f64 float64)
|
||||
GetTime(key string) (t time.Time)
|
||||
GetDuration(key string) (d time.Duration)
|
||||
GetStringSlice(key string) (ss []string)
|
||||
GetStringMap(key string) (sm map[string]interface{})
|
||||
GetStringMapString(key string) (sms map[string]string)
|
||||
GetStringMapStringSlice(key string) (smss map[string][]string)
|
||||
}
|
||||
|
||||
type ctxGinTonic struct {
|
||||
gin.Context
|
||||
}
|
||||
|
||||
func NewGinTonic(c *gin.Context) GinTonic {
|
||||
return &ctxGinTonic{
|
||||
*c.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ctxGinTonic) Deadline() (deadline time.Time, ok bool) {
|
||||
return c.Request.Context().Deadline()
|
||||
}
|
||||
|
||||
func (c *ctxGinTonic) Done() <-chan struct{} {
|
||||
return c.Request.Context().Done()
|
||||
}
|
||||
|
||||
func (c *ctxGinTonic) Err() error {
|
||||
return c.Request.Context().Err()
|
||||
}
|
||||
|
||||
func (c *ctxGinTonic) Value(key interface{}) interface{} {
|
||||
return c.Context.Value(key)
|
||||
}
|
||||
|
||||
func (c *ctxGinTonic) GinContext() *gin.Context {
|
||||
return &c.Context
|
||||
}
|
||||
|
||||
116
ldap/ldap.go
116
ldap/ldap.go
@@ -31,25 +31,14 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
"github.com/nabbar/golib/certificates"
|
||||
"github.com/nabbar/golib/errors"
|
||||
"github.com/nabbar/golib/httpcli"
|
||||
"github.com/nabbar/golib/logger"
|
||||
libcrt "github.com/nabbar/golib/certificates"
|
||||
libctx "github.com/nabbar/golib/context"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
dialTimeout = httpcli.TIMEOUT_10_SEC
|
||||
dialKeepAlive = httpcli.TIMEOUT_5_SEC
|
||||
)
|
||||
|
||||
func SetTimeout(dialerTimeout, dialerKeepAlive time.Duration) {
|
||||
dialTimeout = dialerTimeout
|
||||
dialKeepAlive = dialerKeepAlive
|
||||
}
|
||||
|
||||
//HelperLDAP struct use to manage connection to server and request it.
|
||||
type HelperLDAP struct {
|
||||
Attributes []string
|
||||
@@ -63,21 +52,17 @@ type HelperLDAP struct {
|
||||
}
|
||||
|
||||
//NewLDAP build a new LDAP helper based on config struct given.
|
||||
func NewLDAP(ctx context.Context, cnf *Config, attributes []string) (*HelperLDAP, errors.Error) {
|
||||
func NewLDAP(ctx context.Context, cnf *Config, attributes []string) (*HelperLDAP, liberr.Error) {
|
||||
if cnf == nil {
|
||||
return nil, ErrorEmptyParams.Error(nil)
|
||||
}
|
||||
|
||||
if ctx == nil {
|
||||
return nil, ErrorEmptyParams.Error(nil)
|
||||
}
|
||||
|
||||
return &HelperLDAP{
|
||||
Attributes: attributes,
|
||||
tlsConfig: certificates.GetTLSConfig(cnf.Uri),
|
||||
tlsConfig: libcrt.GetTLSConfig(cnf.Uri),
|
||||
tlsMode: tlsmode_init,
|
||||
config: cnf.Clone(),
|
||||
ctx: ctx,
|
||||
ctx: libctx.IsolateParent(ctx),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -110,11 +95,8 @@ func (lc *HelperLDAP) ForceTLSMode(tlsMode TLSMode, tlsConfig *tls.Config) {
|
||||
}
|
||||
}
|
||||
|
||||
func (lc *HelperLDAP) dialTLS() (*ldap.Conn, errors.Error) {
|
||||
d := net.Dialer{
|
||||
Timeout: dialTimeout,
|
||||
KeepAlive: dialKeepAlive,
|
||||
}
|
||||
func (lc *HelperLDAP) dialTLS() (*ldap.Conn, liberr.Error) {
|
||||
d := net.Dialer{}
|
||||
|
||||
c, err := d.DialContext(lc.ctx, "tcp", lc.config.ServerAddr(true))
|
||||
|
||||
@@ -150,11 +132,8 @@ func (lc *HelperLDAP) dialTLS() (*ldap.Conn, errors.Error) {
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func (lc *HelperLDAP) dial() (*ldap.Conn, errors.Error) {
|
||||
d := net.Dialer{
|
||||
Timeout: dialTimeout,
|
||||
KeepAlive: dialKeepAlive,
|
||||
}
|
||||
func (lc *HelperLDAP) dial() (*ldap.Conn, liberr.Error) {
|
||||
d := net.Dialer{}
|
||||
|
||||
c, err := d.DialContext(lc.ctx, "tcp", lc.config.ServerAddr(true))
|
||||
|
||||
@@ -180,7 +159,7 @@ func (lc *HelperLDAP) dial() (*ldap.Conn, errors.Error) {
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func (lc *HelperLDAP) starttls(l *ldap.Conn) errors.Error {
|
||||
func (lc *HelperLDAP) starttls(l *ldap.Conn) liberr.Error {
|
||||
err := l.StartTLS(lc.tlsConfig)
|
||||
|
||||
if err != nil {
|
||||
@@ -194,10 +173,10 @@ func (lc *HelperLDAP) starttls(l *ldap.Conn) errors.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (lc *HelperLDAP) tryConnect() (TLSMode, errors.Error) {
|
||||
func (lc *HelperLDAP) tryConnect() (TLSMode, liberr.Error) {
|
||||
var (
|
||||
l *ldap.Conn
|
||||
err errors.Error
|
||||
err liberr.Error
|
||||
)
|
||||
|
||||
defer func() {
|
||||
@@ -209,7 +188,7 @@ func (lc *HelperLDAP) tryConnect() (TLSMode, errors.Error) {
|
||||
if lc.config.Portldaps != 0 {
|
||||
l, err = lc.dialTLS()
|
||||
|
||||
logger.DebugLevel.LogErrorCtxf(logger.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSMODE_TLS.String())
|
||||
liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSMODE_TLS.String())
|
||||
|
||||
if err == nil {
|
||||
return TLSMODE_TLS, nil
|
||||
@@ -221,14 +200,14 @@ func (lc *HelperLDAP) tryConnect() (TLSMode, errors.Error) {
|
||||
}
|
||||
|
||||
l, err = lc.dial()
|
||||
logger.DebugLevel.LogErrorCtxf(logger.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSMODE_NONE.String())
|
||||
liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSMODE_NONE.String())
|
||||
|
||||
if err != nil {
|
||||
return tlsmode_init, err
|
||||
}
|
||||
|
||||
err = lc.starttls(l)
|
||||
logger.DebugLevel.LogErrorCtxf(logger.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSMODE_STARTTLS.String())
|
||||
liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSMODE_STARTTLS.String())
|
||||
|
||||
if err == nil {
|
||||
return TLSMODE_STARTTLS, nil
|
||||
@@ -237,7 +216,7 @@ func (lc *HelperLDAP) tryConnect() (TLSMode, errors.Error) {
|
||||
return TLSMODE_NONE, nil
|
||||
}
|
||||
|
||||
func (lc *HelperLDAP) connect() errors.Error {
|
||||
func (lc *HelperLDAP) connect() liberr.Error {
|
||||
if lc.ctx == nil {
|
||||
return ErrorLDAPContext.Error(ErrorEmptyParams.Error(nil))
|
||||
}
|
||||
@@ -249,7 +228,7 @@ func (lc *HelperLDAP) connect() errors.Error {
|
||||
if lc.conn == nil {
|
||||
var (
|
||||
l *ldap.Conn
|
||||
err errors.Error
|
||||
err liberr.Error
|
||||
)
|
||||
|
||||
if lc.tlsMode == tlsmode_init {
|
||||
@@ -292,7 +271,7 @@ func (lc *HelperLDAP) connect() errors.Error {
|
||||
}
|
||||
}
|
||||
|
||||
logger.DebugLevel.Logf("ldap connected with tls mode '%s'", lc.tlsMode.String())
|
||||
liblog.DebugLevel.Logf("ldap connected with tls mode '%s'", lc.tlsMode.String())
|
||||
lc.conn = l
|
||||
}
|
||||
|
||||
@@ -300,12 +279,21 @@ func (lc *HelperLDAP) connect() errors.Error {
|
||||
}
|
||||
|
||||
//Check used to check if connection success (without any bind).
|
||||
func (lc *HelperLDAP) Check() errors.Error {
|
||||
func (lc *HelperLDAP) Check() liberr.Error {
|
||||
if lc.conn == nil {
|
||||
defer func() {
|
||||
if lc.conn != nil {
|
||||
lc.conn.Close()
|
||||
lc.conn = nil
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if err := lc.connect(); err != nil {
|
||||
lc.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
lc.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -318,7 +306,7 @@ func (lc *HelperLDAP) Close() {
|
||||
}
|
||||
|
||||
//AuthUser used to test bind given user uid and password.
|
||||
func (lc *HelperLDAP) AuthUser(username, password string) errors.Error {
|
||||
func (lc *HelperLDAP) AuthUser(username, password string) liberr.Error {
|
||||
|
||||
if err := lc.connect(); err != nil {
|
||||
return err
|
||||
@@ -334,16 +322,16 @@ func (lc *HelperLDAP) AuthUser(username, password string) errors.Error {
|
||||
}
|
||||
|
||||
//Connect used to connect and bind to server.
|
||||
func (lc *HelperLDAP) Connect() errors.Error {
|
||||
func (lc *HelperLDAP) Connect() liberr.Error {
|
||||
if err := lc.AuthUser(lc.bindDN, lc.bindPass); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.DebugLevel.Logf("Bind success on LDAP server %s with tls mode '%s'", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String())
|
||||
liblog.DebugLevel.Logf("Bind success on LDAP server %s with tls mode '%s'", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (lc *HelperLDAP) runSearch(filter string, attributes []string) (*ldap.SearchResult, errors.Error) {
|
||||
func (lc *HelperLDAP) runSearch(filter string, attributes []string) (*ldap.SearchResult, liberr.Error) {
|
||||
var (
|
||||
err error
|
||||
src *ldap.SearchResult
|
||||
@@ -369,11 +357,11 @@ func (lc *HelperLDAP) runSearch(filter string, attributes []string) (*ldap.Searc
|
||||
return nil, ErrorLDAPSearch.ErrorParent(err)
|
||||
}
|
||||
|
||||
logger.DebugLevel.Logf("Search success on server '%s' with tls mode '%s', with filter [%s] and attribute %v", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), filter, attributes)
|
||||
liblog.DebugLevel.Logf("Search success on server '%s' with tls mode '%s', with filter [%s] and attribute %v", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), filter, attributes)
|
||||
return src, nil
|
||||
}
|
||||
|
||||
func (lc *HelperLDAP) getUserName(username string) (string, errors.Error) {
|
||||
func (lc *HelperLDAP) getUserName(username string) (string, liberr.Error) {
|
||||
username = strings.TrimSpace(username)
|
||||
if username == "" {
|
||||
if usr := lc.ParseEntries(lc.bindDN); len(usr) == 0 {
|
||||
@@ -397,9 +385,9 @@ func (lc *HelperLDAP) getUserName(username string) (string, errors.Error) {
|
||||
}
|
||||
|
||||
//UserInfo used to retrieve the information of a given username.
|
||||
func (lc *HelperLDAP) UserInfo(username string) (map[string]string, errors.Error) {
|
||||
func (lc *HelperLDAP) UserInfo(username string) (map[string]string, liberr.Error) {
|
||||
var (
|
||||
err errors.Error
|
||||
err liberr.Error
|
||||
src *ldap.SearchResult
|
||||
userRes map[string]string
|
||||
)
|
||||
@@ -433,14 +421,14 @@ func (lc *HelperLDAP) UserInfo(username string) (map[string]string, errors.Error
|
||||
userRes["DN"] = src.Entries[0].DN
|
||||
}
|
||||
|
||||
logger.DebugLevel.Logf("Map info retrieve in ldap server '%s' with tls mode '%s' about user [%s] : %v", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), username, userRes)
|
||||
liblog.DebugLevel.Logf("Map info retrieve in ldap server '%s' with tls mode '%s' about user [%s] : %v", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), username, userRes)
|
||||
return userRes, nil
|
||||
}
|
||||
|
||||
//GroupInfo used to retrieve the information of a given group cn.
|
||||
func (lc *HelperLDAP) GroupInfo(groupname string) (map[string]interface{}, errors.Error) {
|
||||
func (lc *HelperLDAP) GroupInfo(groupname string) (map[string]interface{}, liberr.Error) {
|
||||
var (
|
||||
err errors.Error
|
||||
err liberr.Error
|
||||
src *ldap.SearchResult
|
||||
grpInfo map[string]interface{}
|
||||
)
|
||||
@@ -461,14 +449,14 @@ func (lc *HelperLDAP) GroupInfo(groupname string) (map[string]interface{}, error
|
||||
}
|
||||
}
|
||||
|
||||
logger.DebugLevel.Logf("Info for group [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), grpInfo)
|
||||
liblog.DebugLevel.Logf("Info for group [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), grpInfo)
|
||||
return grpInfo, nil
|
||||
}
|
||||
|
||||
//UserMemberOf returns the group list of a given user.
|
||||
func (lc *HelperLDAP) UserMemberOf(username string) ([]string, errors.Error) {
|
||||
func (lc *HelperLDAP) UserMemberOf(username string) ([]string, liberr.Error) {
|
||||
var (
|
||||
err errors.Error
|
||||
err liberr.Error
|
||||
src *ldap.SearchResult
|
||||
grp []string
|
||||
)
|
||||
@@ -486,20 +474,20 @@ func (lc *HelperLDAP) UserMemberOf(username string) ([]string, errors.Error) {
|
||||
|
||||
for _, entry := range src.Entries {
|
||||
for _, mmb := range entry.GetAttributeValues("memberOf") {
|
||||
logger.DebugLevel.Logf("Group find for uid '%s' on server '%s' with tls mode '%s' : %v", username, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), mmb)
|
||||
liblog.DebugLevel.Logf("Group find for uid '%s' on server '%s' with tls mode '%s' : %v", username, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), mmb)
|
||||
mmo := lc.ParseEntries(mmb)
|
||||
grp = append(grp, mmo["cn"]...)
|
||||
}
|
||||
}
|
||||
|
||||
logger.DebugLevel.Logf("Groups find for uid '%s' on server '%s' with tls mode '%s' : %v", username, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), grp)
|
||||
liblog.DebugLevel.Logf("Groups find for uid '%s' on server '%s' with tls mode '%s' : %v", username, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), grp)
|
||||
return grp, nil
|
||||
}
|
||||
|
||||
//UserIsInGroup used to check if a given username is a group member of a list of reference group name.
|
||||
func (lc *HelperLDAP) UserIsInGroup(username string, groupname []string) (bool, errors.Error) {
|
||||
func (lc *HelperLDAP) UserIsInGroup(username string, groupname []string) (bool, liberr.Error) {
|
||||
var (
|
||||
err errors.Error
|
||||
err liberr.Error
|
||||
grpMmbr []string
|
||||
)
|
||||
|
||||
@@ -521,9 +509,9 @@ func (lc *HelperLDAP) UserIsInGroup(username string, groupname []string) (bool,
|
||||
}
|
||||
|
||||
//UsersOfGroup used to retrieve the member list of a given group name.
|
||||
func (lc *HelperLDAP) UsersOfGroup(groupname string) ([]string, errors.Error) {
|
||||
func (lc *HelperLDAP) UsersOfGroup(groupname string) ([]string, liberr.Error) {
|
||||
var (
|
||||
err errors.Error
|
||||
err liberr.Error
|
||||
src *ldap.SearchResult
|
||||
grp []string
|
||||
)
|
||||
@@ -542,7 +530,7 @@ func (lc *HelperLDAP) UsersOfGroup(groupname string) ([]string, errors.Error) {
|
||||
}
|
||||
}
|
||||
|
||||
logger.DebugLevel.Logf("Member of groups [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), grp)
|
||||
liblog.DebugLevel.Logf("Member of groups [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), grp)
|
||||
return grp, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user