mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-17 15:56:39 +00:00
Compare commits
11 Commits
revert-283
...
v0.5.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3b809a1d4 | ||
|
|
b2f4322a31 | ||
|
|
d7b69b91b9 | ||
|
|
a3a6283ac6 | ||
|
|
be0c5c887c | ||
|
|
8cc93e0dbe | ||
|
|
24d5f9efac | ||
|
|
c1b162c974 | ||
|
|
612ef98f03 | ||
|
|
605ca03519 | ||
|
|
ff62fec956 |
24
README.md
24
README.md
@@ -126,7 +126,7 @@ Hosted version:
|
||||
```shell
|
||||
brew install wiretrustee/client/wiretrustee
|
||||
```
|
||||
**Installation from binary**
|
||||
**Installation from binary**
|
||||
1. Checkout Wiretrustee [releases](https://github.com/wiretrustee/wiretrustee/releases/latest)
|
||||
2. Download the latest release (**Switch VERSION to the latest**):
|
||||
```shell
|
||||
@@ -138,10 +138,15 @@ Hosted version:
|
||||
sudo mv wiretrusee /usr/local/bin/wiretrustee
|
||||
chmod +x /usr/local/bin/wiretrustee
|
||||
```
|
||||
After that you may need to add /usr/local/bin in your MAC's PATH environment variable:
|
||||
After that you may need to add /usr/local/bin in your PATH environment variable:
|
||||
````shell
|
||||
export PATH=$PATH:/usr/local/bin
|
||||
````
|
||||
4. Install and run the service
|
||||
```shell
|
||||
sudo wiretrustee service install
|
||||
sudo wiretrustee service start
|
||||
```
|
||||
|
||||
#### Windows
|
||||
1. Checkout Wiretrustee [releases](https://github.com/wiretrustee/wiretrustee/releases/latest)
|
||||
@@ -192,6 +197,21 @@ For **Windows** systems:
|
||||
|
||||
3. Repeat on other machines.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
1. If you have specified a wrong `--management-url` (e.g., just by mistake when self-hosting)
|
||||
to override it you can do the following:
|
||||
|
||||
```shell
|
||||
sudo wiretrustee down
|
||||
sudo wiretrustee up --management-url https://<CORRECT HOST:PORT>/
|
||||
```
|
||||
|
||||
2. If you are using self-hosted version and haven't specified `--management-url`, the client app will use the default URL
|
||||
which is ```https://api.wiretrustee.com:33073```.
|
||||
|
||||
To override it see solution #1 above.
|
||||
|
||||
### Running Dashboard, Management, Signal and Coturn
|
||||
See [Self-Hosting Guide](https://docs.wiretrustee.com/getting-started/self-hosting)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/wiretrustee/wiretrustee/util"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -16,6 +17,12 @@ var downCmd = &cobra.Command{
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
SetFlagsFromEnvVars()
|
||||
|
||||
err := util.InitLog(logLevel, logFile)
|
||||
if err != nil {
|
||||
log.Errorf("failed initializing log %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
|
||||
defer cancel()
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package cmd
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/wiretrustee/wiretrustee/util"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -16,6 +17,13 @@ var loginCmd = &cobra.Command{
|
||||
Short: "login to the Wiretrustee Management Service (first run)",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
SetFlagsFromEnvVars()
|
||||
|
||||
err := util.InitLog(logLevel, logFile)
|
||||
if err != nil {
|
||||
log.Errorf("failed initializing log %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := internal.CtxInitState(context.Background())
|
||||
|
||||
// workaround to run without service
|
||||
|
||||
@@ -2,35 +2,17 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/wiretrustee/wiretrustee/client/internal"
|
||||
"github.com/wiretrustee/wiretrustee/iface"
|
||||
mgmt "github.com/wiretrustee/wiretrustee/management/server"
|
||||
"github.com/wiretrustee/wiretrustee/util"
|
||||
)
|
||||
|
||||
var mgmAddr string
|
||||
|
||||
func TestLogin_Start(t *testing.T) {
|
||||
config := &mgmt.Config{}
|
||||
_, err := util.ReadJson("../testdata/management.json", config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testDir := t.TempDir()
|
||||
config.Datadir = testDir
|
||||
err = util.CopyFileContents("../testdata/store.json", filepath.Join(testDir, "store.json"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, listener := startManagement(t, config)
|
||||
mgmAddr = listener.Addr().String()
|
||||
}
|
||||
|
||||
func TestLogin(t *testing.T) {
|
||||
mgmAddr := startTestingServices(t)
|
||||
|
||||
tempDir := t.TempDir()
|
||||
confPath := tempDir + "/config.json"
|
||||
mgmtURL := fmt.Sprintf("http://%s", mgmAddr)
|
||||
|
||||
@@ -45,6 +45,14 @@ func (p *program) Start(svc service.Service) error {
|
||||
}
|
||||
defer listen.Close()
|
||||
|
||||
if split[0] == "unix" {
|
||||
err = os.Chmod(split[1], 0666)
|
||||
if err != nil {
|
||||
log.Errorf("failed setting daemon permissions: %v", split[1])
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
serverInstance := server.New(p.ctx, managementURL, configPath, stopCh, cleanupCh)
|
||||
if err := serverInstance.Start(); err != nil {
|
||||
log.Fatalf("failed start daemon: %v", err)
|
||||
|
||||
@@ -2,6 +2,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/wiretrustee/wiretrustee/util"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -16,6 +17,13 @@ var statusCmd = &cobra.Command{
|
||||
Short: "status of the Wiretrustee Service",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
SetFlagsFromEnvVars()
|
||||
|
||||
err := util.InitLog(logLevel, logFile)
|
||||
if err != nil {
|
||||
log.Errorf("failed initializing log %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := internal.CtxInitState(context.Background())
|
||||
|
||||
conn, err := DialClientGRPCServer(ctx, daemonAddr)
|
||||
|
||||
@@ -2,7 +2,9 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/wiretrustee/wiretrustee/util"
|
||||
"net"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -15,6 +17,28 @@ import (
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func startTestingServices(t *testing.T) string {
|
||||
config := &mgmt.Config{}
|
||||
_, err := util.ReadJson("../testdata/management.json", config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testDir := t.TempDir()
|
||||
config.Datadir = testDir
|
||||
err = util.CopyFileContents("../testdata/store.json", filepath.Join(testDir, "store.json"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, signalLis := startSignal(t)
|
||||
signalAddr := signalLis.Addr().String()
|
||||
config.Signal.URI = signalAddr
|
||||
|
||||
_, mgmLis := startManagement(t, config)
|
||||
mgmAddr := mgmLis.Addr().String()
|
||||
return mgmAddr
|
||||
}
|
||||
|
||||
func startSignal(t *testing.T) (*grpc.Server, net.Listener) {
|
||||
lis, err := net.Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
|
||||
@@ -3,6 +3,7 @@ package cmd
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/wiretrustee/wiretrustee/util"
|
||||
|
||||
"github.com/wiretrustee/wiretrustee/client/internal"
|
||||
"github.com/wiretrustee/wiretrustee/client/proto"
|
||||
@@ -13,6 +14,13 @@ var upCmd = &cobra.Command{
|
||||
Short: "install, login and start wiretrustee client",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
SetFlagsFromEnvVars()
|
||||
|
||||
err := util.InitLog(logLevel, logFile)
|
||||
if err != nil {
|
||||
log.Errorf("failed initializing log %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := internal.CtxInitState(cmd.Context())
|
||||
|
||||
// workaround to run without service
|
||||
|
||||
@@ -2,37 +2,15 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/wiretrustee/wiretrustee/client/internal"
|
||||
mgmt "github.com/wiretrustee/wiretrustee/management/server"
|
||||
"github.com/wiretrustee/wiretrustee/util"
|
||||
)
|
||||
|
||||
func TestUpDaemon_Start(t *testing.T) {
|
||||
config := &mgmt.Config{}
|
||||
_, err := util.ReadJson("../testdata/management.json", config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testDir := t.TempDir()
|
||||
config.Datadir = testDir
|
||||
err = util.CopyFileContents("../testdata/store.json", filepath.Join(testDir, "store.json"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, signalLis := startSignal(t)
|
||||
signalAddr = signalLis.Addr().String()
|
||||
config.Signal.URI = signalAddr
|
||||
|
||||
_, mgmLis := startManagement(t, config)
|
||||
mgmAddr = mgmLis.Addr().String()
|
||||
}
|
||||
|
||||
func TestUpDaemon(t *testing.T) {
|
||||
mgmAddr := startTestingServices(t)
|
||||
|
||||
tempDir := t.TempDir()
|
||||
confPath := tempDir + "/config.json"
|
||||
|
||||
|
||||
@@ -2,42 +2,20 @@ package cmd
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/wiretrustee/wiretrustee/iface"
|
||||
mgmt "github.com/wiretrustee/wiretrustee/management/server"
|
||||
"github.com/wiretrustee/wiretrustee/util"
|
||||
)
|
||||
|
||||
var (
|
||||
signalAddr string
|
||||
cliAddr string
|
||||
//signalAddr string
|
||||
cliAddr string
|
||||
)
|
||||
|
||||
func TestUp_Start(t *testing.T) {
|
||||
config := &mgmt.Config{}
|
||||
_, err := util.ReadJson("../testdata/management.json", config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testDir := t.TempDir()
|
||||
config.Datadir = testDir
|
||||
err = util.CopyFileContents("../testdata/store.json", filepath.Join(testDir, "store.json"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, signalLis := startSignal(t)
|
||||
signalAddr = signalLis.Addr().String()
|
||||
config.Signal.URI = signalAddr
|
||||
|
||||
_, mgmLis := startManagement(t, config)
|
||||
mgmAddr = mgmLis.Addr().String()
|
||||
}
|
||||
|
||||
func TestUp(t *testing.T) {
|
||||
mgmAddr := startTestingServices(t)
|
||||
|
||||
tempDir := t.TempDir()
|
||||
confPath := tempDir + "/config.json"
|
||||
mgmtURL, err := url.Parse("http://" + mgmAddr)
|
||||
@@ -66,7 +44,7 @@ func TestUp(t *testing.T) {
|
||||
}()
|
||||
time.Sleep(time.Second * 2)
|
||||
|
||||
timeout := 15 * time.Second
|
||||
timeout := 30 * time.Second
|
||||
timeoutChannel := time.After(timeout)
|
||||
for {
|
||||
select {
|
||||
|
||||
@@ -97,6 +97,7 @@ EnVar::SetHKLM
|
||||
EnVar::AddValueEx "path" "$INSTDIR"
|
||||
|
||||
Exec '"$INSTDIR\${MAIN_APP_EXE}" service install'
|
||||
Exec '"$INSTDIR\${MAIN_APP_EXE}" service start'
|
||||
# sleep a bit for visibility
|
||||
Sleep 1000
|
||||
SectionEnd
|
||||
|
||||
@@ -86,12 +86,18 @@ func ReadConfig(managementURL string, configPath string) (*Config, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if managementURL != "" {
|
||||
if managementURL != "" && config.ManagementURL.String() != managementURL {
|
||||
URL, err := parseManagementURL(managementURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.ManagementURL = URL
|
||||
// since we have new management URL, we need to update config file
|
||||
err = util.WriteJson(configPath, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Infof("new Management URL provided, updated to %s (old value %s)", managementURL, config.ManagementURL)
|
||||
}
|
||||
|
||||
return config, err
|
||||
|
||||
60
client/internal/config_test.go
Normal file
60
client/internal/config_test.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/wiretrustee/wiretrustee/util"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadConfig(t *testing.T) {
|
||||
|
||||
}
|
||||
func TestGetConfig(t *testing.T) {
|
||||
|
||||
managementURL := "https://test.management.url:33071"
|
||||
path := filepath.Join(t.TempDir(), "config.json")
|
||||
preSharedKey := "preSharedKey"
|
||||
|
||||
// case 1: new config has to be generated
|
||||
config, err := GetConfig(managementURL, path, preSharedKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, config.ManagementURL.String(), managementURL)
|
||||
assert.Equal(t, config.PreSharedKey, preSharedKey)
|
||||
|
||||
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
|
||||
t.Errorf("config file was expected to be created under path %s", path)
|
||||
}
|
||||
|
||||
// case 2: existing config -> fetch it
|
||||
config, err = GetConfig(managementURL, path, preSharedKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, config.ManagementURL.String(), managementURL)
|
||||
assert.Equal(t, config.PreSharedKey, preSharedKey)
|
||||
|
||||
// case 3: existing config, but new managementURL has been provided -> update config
|
||||
newManagementURL := "https://test.newManagement.url:33071"
|
||||
config, err = GetConfig(newManagementURL, path, preSharedKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, config.ManagementURL.String(), newManagementURL)
|
||||
assert.Equal(t, config.PreSharedKey, preSharedKey)
|
||||
|
||||
// read once more to make sure that config file has been updated with the new management URL
|
||||
readConf, err := util.ReadJson(path, config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, readConf.(*Config).ManagementURL.String(), newManagementURL)
|
||||
|
||||
}
|
||||
@@ -85,7 +85,7 @@ type Engine struct {
|
||||
udpMuxConn *net.UDPConn
|
||||
udpMuxConnSrflx *net.UDPConn
|
||||
|
||||
// networkSerial is the latest Serial (state ID) of the network sent by the Management service
|
||||
// networkSerial is the latest CurrentSerial (state ID) of the network sent by the Management service
|
||||
networkSerial uint64
|
||||
}
|
||||
|
||||
@@ -123,6 +123,10 @@ func (e *Engine) Stop() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// very ugly but we want to remove peers from the WireGuard interface first before removing interface.
|
||||
// Removing peers happens in the conn.CLose() asynchronously
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
log.Debugf("removing Wiretrustee interface %s", e.config.WgIfaceName)
|
||||
if e.wgInterface.Interface != nil {
|
||||
err = e.wgInterface.Close()
|
||||
@@ -489,7 +493,7 @@ func (e Engine) connWorker(conn *peer.Conn, peerKey string) {
|
||||
|
||||
// if peer has been removed -> give up
|
||||
if !e.peerExists(peerKey) {
|
||||
log.Infof("peer %s doesn't exist anymore, won't retry connection", peerKey)
|
||||
log.Debugf("peer %s doesn't exist anymore, won't retry connection", peerKey)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ func TestEngine_UpdateNetworkMap(t *testing.T) {
|
||||
expectedSerial: 1,
|
||||
}
|
||||
|
||||
// 2nd case - one extra peer added and network map has Serial grater than local => apply the update
|
||||
// 2nd case - one extra peer added and network map has CurrentSerial grater than local => apply the update
|
||||
case2 := testCase{
|
||||
name: "input with an old peer and a new peer to add",
|
||||
networkMap: &mgmtProto.NetworkMap{
|
||||
|
||||
@@ -153,7 +153,7 @@ func (conn *Conn) Open() error {
|
||||
defer func() {
|
||||
err := conn.cleanup()
|
||||
if err != nil {
|
||||
log.Errorf("error while cleaning up peer connection %s: %v", conn.config.Key, err)
|
||||
log.Warnf("error while cleaning up peer connection %s: %v", conn.config.Key, err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -64,6 +64,7 @@ func (s *Server) Start() error {
|
||||
log.Warnf("no config file, skip connection stage: %v", err)
|
||||
return nil
|
||||
}
|
||||
s.config = config
|
||||
|
||||
go func() {
|
||||
if err := internal.RunClient(ctx, config, s.stopCh, s.cleanupCh); err != nil {
|
||||
|
||||
@@ -836,7 +836,7 @@ type NetworkMap struct {
|
||||
// Serial is an ID of the network state to be used by clients to order updates.
|
||||
// The larger the Serial the newer the configuration.
|
||||
// E.g. the client app should keep track of this id locally and discard all the configurations with a lower value
|
||||
Serial uint64 `protobuf:"varint,1,opt,name=Serial,proto3" json:"Serial,omitempty"`
|
||||
Serial uint64 `protobuf:"varint,1,opt,name=CurrentSerial,proto3" json:"CurrentSerial,omitempty"`
|
||||
// PeerConfig represents configuration of a peer
|
||||
PeerConfig *PeerConfig `protobuf:"bytes,2,opt,name=peerConfig,proto3" json:"peerConfig,omitempty"`
|
||||
// RemotePeerConfig represents a list of remote peers that the receiver can connect to
|
||||
|
||||
@@ -248,11 +248,16 @@ func (am *DefaultAccountManager) updateAccountDomainAttributes(account *Account,
|
||||
func (am *DefaultAccountManager) handleExistingUserAccount(existingAcc *Account, domainAcc *Account, claims jwtclaims.AuthorizationClaims) error {
|
||||
var err error
|
||||
|
||||
if domainAcc == nil || existingAcc.Id != domainAcc.Id {
|
||||
if domainAcc != nil && existingAcc.Id != domainAcc.Id {
|
||||
err = am.updateAccountDomainAttributes(existingAcc, claims, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = am.updateAccountDomainAttributes(existingAcc, claims, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// we should register the account ID to this user's metadata in our IDP manager
|
||||
@@ -268,24 +273,21 @@ func (am *DefaultAccountManager) handleExistingUserAccount(existingAcc *Account,
|
||||
// otherwise it will create a new account and make it primary account for the domain.
|
||||
func (am *DefaultAccountManager) handleNewUserAccount(domainAcc *Account, claims jwtclaims.AuthorizationClaims) (*Account, error) {
|
||||
var (
|
||||
account *Account
|
||||
primaryAccount bool
|
||||
account *Account
|
||||
err error
|
||||
)
|
||||
lowerDomain := strings.ToLower(claims.Domain)
|
||||
// if domain already has a primary account, add regular user
|
||||
if domainAcc != nil {
|
||||
account = domainAcc
|
||||
account.Users[claims.UserId] = NewRegularUser(claims.UserId)
|
||||
primaryAccount = false
|
||||
} else {
|
||||
account = NewAccount(claims.UserId, lowerDomain)
|
||||
account.Users[claims.UserId] = NewAdminUser(claims.UserId)
|
||||
primaryAccount = true
|
||||
}
|
||||
|
||||
err := am.updateAccountDomainAttributes(account, claims, primaryAccount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
err = am.updateAccountDomainAttributes(account, claims, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = am.updateIDPMetadata(claims.UserId, account.Id)
|
||||
@@ -316,8 +318,16 @@ func (am *DefaultAccountManager) handleNewUserAccount(domainAcc *Account, claims
|
||||
func (am *DefaultAccountManager) GetAccountWithAuthorizationClaims(claims jwtclaims.AuthorizationClaims) (*Account, error) {
|
||||
// if Account ID is part of the claims
|
||||
// it means that we've already classified the domain and user has an account
|
||||
if claims.DomainCategory != PrivateCategory || claims.AccountId != "" {
|
||||
if claims.DomainCategory != PrivateCategory {
|
||||
return am.GetAccountByUserOrAccountId(claims.UserId, claims.AccountId, claims.Domain)
|
||||
} else if claims.AccountId != "" {
|
||||
accountFromID, err := am.GetAccountByUserOrAccountId(claims.UserId, claims.AccountId, claims.Domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if accountFromID.DomainCategory == PrivateCategory || claims.DomainCategory != PrivateCategory {
|
||||
return accountFromID, nil
|
||||
}
|
||||
}
|
||||
|
||||
am.mux.Lock()
|
||||
|
||||
@@ -39,13 +39,16 @@ func TestDefaultAccountManager_GetAccountWithAuthorizationClaims(t *testing.T) {
|
||||
type initUserParams jwtclaims.AuthorizationClaims
|
||||
|
||||
type test struct {
|
||||
name string
|
||||
inputClaims jwtclaims.AuthorizationClaims
|
||||
inputInitUserParams initUserParams
|
||||
inputUpdateAttrs bool
|
||||
testingFunc require.ComparisonAssertionFunc
|
||||
expectedMSG string
|
||||
expectedUserRole UserRole
|
||||
name string
|
||||
inputClaims jwtclaims.AuthorizationClaims
|
||||
inputInitUserParams initUserParams
|
||||
inputUpdateAttrs bool
|
||||
inputUpdateClaimAccount bool
|
||||
testingFunc require.ComparisonAssertionFunc
|
||||
expectedMSG string
|
||||
expectedUserRole UserRole
|
||||
expectedDomainCategory string
|
||||
expectedPrimaryDomainStatus bool
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -66,10 +69,12 @@ func TestDefaultAccountManager_GetAccountWithAuthorizationClaims(t *testing.T) {
|
||||
UserId: "pub-domain-user",
|
||||
DomainCategory: PublicCategory,
|
||||
},
|
||||
inputInitUserParams: defaultInitAccount,
|
||||
testingFunc: require.NotEqual,
|
||||
expectedMSG: "account IDs shouldn't match",
|
||||
expectedUserRole: UserRoleAdmin,
|
||||
inputInitUserParams: defaultInitAccount,
|
||||
testingFunc: require.NotEqual,
|
||||
expectedMSG: "account IDs shouldn't match",
|
||||
expectedUserRole: UserRoleAdmin,
|
||||
expectedDomainCategory: "",
|
||||
expectedPrimaryDomainStatus: false,
|
||||
}
|
||||
|
||||
initUnknown := defaultInitAccount
|
||||
@@ -83,10 +88,12 @@ func TestDefaultAccountManager_GetAccountWithAuthorizationClaims(t *testing.T) {
|
||||
UserId: "unknown-domain-user",
|
||||
DomainCategory: UnknownCategory,
|
||||
},
|
||||
inputInitUserParams: initUnknown,
|
||||
testingFunc: require.NotEqual,
|
||||
expectedMSG: "account IDs shouldn't match",
|
||||
expectedUserRole: UserRoleAdmin,
|
||||
inputInitUserParams: initUnknown,
|
||||
testingFunc: require.NotEqual,
|
||||
expectedMSG: "account IDs shouldn't match",
|
||||
expectedUserRole: UserRoleAdmin,
|
||||
expectedDomainCategory: "",
|
||||
expectedPrimaryDomainStatus: false,
|
||||
}
|
||||
|
||||
testCase3 := test{
|
||||
@@ -96,10 +103,12 @@ func TestDefaultAccountManager_GetAccountWithAuthorizationClaims(t *testing.T) {
|
||||
UserId: "pvt-domain-user",
|
||||
DomainCategory: PrivateCategory,
|
||||
},
|
||||
inputInitUserParams: defaultInitAccount,
|
||||
testingFunc: require.NotEqual,
|
||||
expectedMSG: "account IDs shouldn't match",
|
||||
expectedUserRole: UserRoleAdmin,
|
||||
inputInitUserParams: defaultInitAccount,
|
||||
testingFunc: require.NotEqual,
|
||||
expectedMSG: "account IDs shouldn't match",
|
||||
expectedUserRole: UserRoleAdmin,
|
||||
expectedDomainCategory: PrivateCategory,
|
||||
expectedPrimaryDomainStatus: true,
|
||||
}
|
||||
|
||||
privateInitAccount := defaultInitAccount
|
||||
@@ -113,11 +122,13 @@ func TestDefaultAccountManager_GetAccountWithAuthorizationClaims(t *testing.T) {
|
||||
UserId: "pvt-domain-user",
|
||||
DomainCategory: PrivateCategory,
|
||||
},
|
||||
inputUpdateAttrs: true,
|
||||
inputInitUserParams: privateInitAccount,
|
||||
testingFunc: require.Equal,
|
||||
expectedMSG: "account IDs should match",
|
||||
expectedUserRole: UserRoleUser,
|
||||
inputUpdateAttrs: true,
|
||||
inputInitUserParams: privateInitAccount,
|
||||
testingFunc: require.Equal,
|
||||
expectedMSG: "account IDs should match",
|
||||
expectedUserRole: UserRoleUser,
|
||||
expectedDomainCategory: PrivateCategory,
|
||||
expectedPrimaryDomainStatus: true,
|
||||
}
|
||||
|
||||
testCase5 := test{
|
||||
@@ -127,13 +138,30 @@ func TestDefaultAccountManager_GetAccountWithAuthorizationClaims(t *testing.T) {
|
||||
UserId: defaultInitAccount.UserId,
|
||||
DomainCategory: PrivateCategory,
|
||||
},
|
||||
inputInitUserParams: defaultInitAccount,
|
||||
testingFunc: require.Equal,
|
||||
expectedMSG: "account IDs should match",
|
||||
expectedUserRole: UserRoleAdmin,
|
||||
inputInitUserParams: defaultInitAccount,
|
||||
testingFunc: require.Equal,
|
||||
expectedMSG: "account IDs should match",
|
||||
expectedUserRole: UserRoleAdmin,
|
||||
expectedDomainCategory: PrivateCategory,
|
||||
expectedPrimaryDomainStatus: true,
|
||||
}
|
||||
|
||||
for _, testCase := range []test{testCase1, testCase2, testCase3, testCase4, testCase5} {
|
||||
testCase6 := test{
|
||||
name: "Existing Account Id With Existing Reclassified Private Domain",
|
||||
inputClaims: jwtclaims.AuthorizationClaims{
|
||||
Domain: defaultInitAccount.Domain,
|
||||
UserId: defaultInitAccount.UserId,
|
||||
DomainCategory: PrivateCategory,
|
||||
},
|
||||
inputUpdateClaimAccount: true,
|
||||
inputInitUserParams: defaultInitAccount,
|
||||
testingFunc: require.Equal,
|
||||
expectedMSG: "account IDs should match",
|
||||
expectedUserRole: UserRoleAdmin,
|
||||
expectedDomainCategory: PrivateCategory,
|
||||
expectedPrimaryDomainStatus: true,
|
||||
}
|
||||
for _, testCase := range []test{testCase1, testCase2, testCase3, testCase4, testCase5, testCase6} {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
|
||||
manager, err := createManager(t)
|
||||
@@ -147,12 +175,18 @@ func TestDefaultAccountManager_GetAccountWithAuthorizationClaims(t *testing.T) {
|
||||
require.NoError(t, err, "update init user failed")
|
||||
}
|
||||
|
||||
if testCase.inputUpdateClaimAccount {
|
||||
testCase.inputClaims.AccountId = initAccount.Id
|
||||
}
|
||||
|
||||
account, err := manager.GetAccountWithAuthorizationClaims(testCase.inputClaims)
|
||||
require.NoError(t, err, "support function failed")
|
||||
|
||||
testCase.testingFunc(t, initAccount.Id, account.Id, testCase.expectedMSG)
|
||||
|
||||
require.EqualValues(t, testCase.expectedUserRole, account.Users[testCase.inputClaims.UserId].Role, "user role should match")
|
||||
require.EqualValues(t, testCase.expectedUserRole, account.Users[testCase.inputClaims.UserId].Role, "expected user role should match")
|
||||
require.EqualValues(t, testCase.expectedDomainCategory, account.DomainCategory, "expected account domain category should match")
|
||||
require.EqualValues(t, testCase.expectedPrimaryDomainStatus, account.IsDomainPrimaryAccount, "expected account primary status should match")
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -363,7 +397,7 @@ func TestAccountManager_AddPeer(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
serial := account.Network.Serial() //should be 0
|
||||
serial := account.Network.CurrentSerial() //should be 0
|
||||
|
||||
var setupKey *SetupKey
|
||||
for _, key := range account.SetupKeys {
|
||||
@@ -375,8 +409,8 @@ func TestAccountManager_AddPeer(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
if account.Network.serial != 0 {
|
||||
t.Errorf("expecting account network to have an initial serial=0")
|
||||
if account.Network.Serial != 0 {
|
||||
t.Errorf("expecting account network to have an initial Serial=0")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -412,8 +446,8 @@ func TestAccountManager_AddPeer(t *testing.T) {
|
||||
t.Errorf("expecting just added peer to have IP = %s, got %s", expectedPeerIP, peer.IP.String())
|
||||
}
|
||||
|
||||
if account.Network.Serial() != 1 {
|
||||
t.Errorf("expecting Network serial=%d to be incremented by 1 and be equal to %d when adding new peer to account", serial, account.Network.Serial())
|
||||
if account.Network.CurrentSerial() != 1 {
|
||||
t.Errorf("expecting Network Serial=%d to be incremented by 1 and be equal to %d when adding new peer to account", serial, account.Network.CurrentSerial())
|
||||
}
|
||||
|
||||
}
|
||||
@@ -464,8 +498,8 @@ func TestAccountManager_DeletePeer(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
if account.Network.Serial() != 2 {
|
||||
t.Errorf("expecting Network serial=%d to be incremented and be equal to 2 after adding and deleteing a peer", account.Network.Serial())
|
||||
if account.Network.CurrentSerial() != 2 {
|
||||
t.Errorf("expecting Network Serial=%d to be incremented and be equal to 2 after adding and deleteing a peer", account.Network.CurrentSerial())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ func (s *Server) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest) (*Pe
|
||||
peersToSend = append(peersToSend, p)
|
||||
}
|
||||
}
|
||||
update := toSyncResponse(s.config, peer, peersToSend, nil, networkMap.Network.Serial())
|
||||
update := toSyncResponse(s.config, peer, peersToSend, nil, networkMap.Network.CurrentSerial())
|
||||
err = s.peersUpdateManager.SendUpdate(remotePeer.Key, &UpdateMessage{Update: update})
|
||||
if err != nil {
|
||||
// todo rethink if we should keep this return
|
||||
@@ -362,7 +362,7 @@ func (s *Server) sendInitialSync(peerKey wgtypes.Key, peer *Peer, srv proto.Mana
|
||||
} else {
|
||||
turnCredentials = nil
|
||||
}
|
||||
plainResp := toSyncResponse(s.config, peer, networkMap.Peers, turnCredentials, networkMap.Network.Serial())
|
||||
plainResp := toSyncResponse(s.config, peer, networkMap.Peers, turnCredentials, networkMap.Network.CurrentSerial())
|
||||
|
||||
encryptedResp, err := encryption.EncryptMessage(peerKey, s.wgKey, plainResp)
|
||||
if err != nil {
|
||||
|
||||
@@ -23,9 +23,18 @@ type Auth0Manager struct {
|
||||
|
||||
// Auth0ClientConfig auth0 manager client configurations
|
||||
type Auth0ClientConfig struct {
|
||||
Audience string `json:"audiance"`
|
||||
Audience string
|
||||
AuthIssuer string
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
GrantType string
|
||||
}
|
||||
|
||||
// auth0JWTRequest payload struct to request a JWT Token
|
||||
type auth0JWTRequest struct {
|
||||
Audience string `json:"audience"`
|
||||
AuthIssuer string `json:"auth_issuer"`
|
||||
ClientId string `json:"client_id"`
|
||||
ClientID string `json:"client_id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
GrantType string `json:"grant_type"`
|
||||
}
|
||||
@@ -40,11 +49,10 @@ type Auth0Credentials struct {
|
||||
}
|
||||
|
||||
// NewAuth0Manager creates a new instance of the Auth0Manager
|
||||
func NewAuth0Manager(config Auth0ClientConfig) *Auth0Manager {
|
||||
func NewAuth0Manager(config Auth0ClientConfig) (*Auth0Manager, error) {
|
||||
|
||||
httpTransport := http.DefaultTransport.(*http.Transport).Clone()
|
||||
httpTransport.MaxIdleConns = 5
|
||||
httpTransport.IdleConnTimeout = 30
|
||||
|
||||
httpClient := &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
@@ -53,6 +61,18 @@ func NewAuth0Manager(config Auth0ClientConfig) *Auth0Manager {
|
||||
|
||||
helper := JsonParser{}
|
||||
|
||||
if config.ClientID == "" || config.ClientSecret == "" || config.GrantType == "" || config.Audience == "" || config.AuthIssuer == "" {
|
||||
return nil, fmt.Errorf("auth0 idp configuration is not complete")
|
||||
}
|
||||
|
||||
if config.GrantType != "client_credentials" {
|
||||
return nil, fmt.Errorf("auth0 idp configuration failed. Grant Type should be client_credentials")
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(strings.ToLower(config.AuthIssuer), "https://") {
|
||||
return nil, fmt.Errorf("auth0 idp configuration failed. AuthIssuer should contain https://")
|
||||
}
|
||||
|
||||
credentials := &Auth0Credentials{
|
||||
clientConfig: config,
|
||||
httpClient: httpClient,
|
||||
@@ -63,7 +83,7 @@ func NewAuth0Manager(config Auth0ClientConfig) *Auth0Manager {
|
||||
credentials: credentials,
|
||||
httpClient: httpClient,
|
||||
helper: helper,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// jwtStillValid returns true if the token still valid and have enough time to be used and get a response from Auth0
|
||||
@@ -76,7 +96,7 @@ func (c *Auth0Credentials) requestJWTToken() (*http.Response, error) {
|
||||
var res *http.Response
|
||||
url := c.clientConfig.AuthIssuer + "/oauth/token"
|
||||
|
||||
p, err := c.helper.Marshal(c.clientConfig)
|
||||
p, err := c.helper.Marshal(auth0JWTRequest(c.clientConfig))
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
@@ -89,6 +109,8 @@ func (c *Auth0Credentials) requestJWTToken() (*http.Response, error) {
|
||||
|
||||
req.Header.Add("content-type", "application/json")
|
||||
|
||||
log.Debug("requesting new jwt token for idp manager")
|
||||
|
||||
res, err = c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return res, err
|
||||
@@ -187,6 +209,8 @@ func (am *Auth0Manager) UpdateUserAppMetadata(userId string, appMetadata AppMeta
|
||||
req.Header.Add("authorization", "Bearer "+jwtToken.AccessToken)
|
||||
req.Header.Add("content-type", "application/json")
|
||||
|
||||
log.Debugf("updating metadata for user %s", userId)
|
||||
|
||||
res, err := am.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -3,6 +3,7 @@ package idp
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/stretchr/testify/require"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -402,3 +403,64 @@ func TestAuth0_UpdateUserAppMetadata(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewAuth0Manager(t *testing.T) {
|
||||
type test struct {
|
||||
name string
|
||||
inputConfig Auth0ClientConfig
|
||||
assertErrFunc require.ErrorAssertionFunc
|
||||
assertErrFuncMessage string
|
||||
}
|
||||
|
||||
defaultTestConfig := Auth0ClientConfig{
|
||||
AuthIssuer: "https://abc-auth0.eu.auth0.com",
|
||||
Audience: "https://abc-auth0.eu.auth0.com/api/v2/",
|
||||
ClientID: "abcdefg",
|
||||
ClientSecret: "supersecret",
|
||||
GrantType: "client_credentials",
|
||||
}
|
||||
|
||||
testCase1 := test{
|
||||
name: "Good Scenario With Config",
|
||||
inputConfig: defaultTestConfig,
|
||||
assertErrFunc: require.NoError,
|
||||
assertErrFuncMessage: "shouldn't return error",
|
||||
}
|
||||
|
||||
testCase2Config := defaultTestConfig
|
||||
testCase2Config.ClientID = ""
|
||||
|
||||
testCase2 := test{
|
||||
name: "Missing Configuration",
|
||||
inputConfig: testCase2Config,
|
||||
assertErrFunc: require.Error,
|
||||
assertErrFuncMessage: "shouldn't return error when field empty",
|
||||
}
|
||||
|
||||
testCase3Config := defaultTestConfig
|
||||
testCase3Config.AuthIssuer = "abc-auth0.eu.auth0.com"
|
||||
|
||||
testCase3 := test{
|
||||
name: "Wrong Auth Issuer Format",
|
||||
inputConfig: testCase3Config,
|
||||
assertErrFunc: require.Error,
|
||||
assertErrFuncMessage: "should return error when wrong auth issuer format",
|
||||
}
|
||||
|
||||
testCase4Config := defaultTestConfig
|
||||
testCase4Config.GrantType = "spa"
|
||||
|
||||
testCase4 := test{
|
||||
name: "Wrong Grant Type",
|
||||
inputConfig: testCase4Config,
|
||||
assertErrFunc: require.Error,
|
||||
assertErrFuncMessage: "should return error when wrong grant type",
|
||||
}
|
||||
|
||||
for _, testCase := range []test{testCase1, testCase2, testCase3, testCase4} {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
_, err := NewAuth0Manager(testCase.inputConfig)
|
||||
testCase.assertErrFunc(t, err, testCase.assertErrFuncMessage)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ func NewManager(config Config) (Manager, error) {
|
||||
case "none", "":
|
||||
return nil, nil
|
||||
case "auth0":
|
||||
return NewAuth0Manager(config.Auth0ClientCredentials), nil
|
||||
return NewAuth0Manager(config.Auth0ClientCredentials)
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid manager type: %s", config.ManagerType)
|
||||
}
|
||||
|
||||
@@ -258,7 +258,7 @@ func Test_SyncProtocol(t *testing.T) {
|
||||
}
|
||||
|
||||
if networkMap.GetSerial() <= 0 {
|
||||
t.Fatalf("expecting SyncResponse to have NetworkMap with a positive Network Serial, actual %d", networkMap.GetSerial())
|
||||
t.Fatalf("expecting SyncResponse to have NetworkMap with a positive Network CurrentSerial, actual %d", networkMap.GetSerial())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,34 +22,34 @@ type Network struct {
|
||||
Id string
|
||||
Net net.IPNet
|
||||
Dns string
|
||||
// serial is an ID that increments by 1 when any change to the network happened (e.g. new peer has been added).
|
||||
// Serial is an ID that increments by 1 when any change to the network happened (e.g. new peer has been added).
|
||||
// Used to synchronize state to the client apps.
|
||||
serial uint64
|
||||
Serial uint64
|
||||
|
||||
mu sync.Mutex `json:"-"`
|
||||
}
|
||||
|
||||
// NewNetwork creates a new Network initializing it with a serial=0
|
||||
// NewNetwork creates a new Network initializing it with a Serial=0
|
||||
func NewNetwork() *Network {
|
||||
return &Network{
|
||||
Id: xid.New().String(),
|
||||
Net: net.IPNet{IP: net.ParseIP("100.64.0.0"), Mask: net.IPMask{255, 192, 0, 0}},
|
||||
Dns: "",
|
||||
serial: 0}
|
||||
Serial: 0}
|
||||
}
|
||||
|
||||
// IncSerial increments serial by 1 reflecting that the network state has been changed
|
||||
// IncSerial increments Serial by 1 reflecting that the network state has been changed
|
||||
func (n *Network) IncSerial() {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
n.serial = n.serial + 1
|
||||
n.Serial = n.Serial + 1
|
||||
}
|
||||
|
||||
// Serial returns the Network.serial of the network (latest state id)
|
||||
func (n *Network) Serial() uint64 {
|
||||
// CurrentSerial returns the Network.Serial of the network (latest state id)
|
||||
func (n *Network) CurrentSerial() uint64 {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
return n.serial
|
||||
return n.Serial
|
||||
}
|
||||
|
||||
func (n *Network) Copy() *Network {
|
||||
@@ -57,7 +57,7 @@ func (n *Network) Copy() *Network {
|
||||
Id: n.Id,
|
||||
Net: n.Net,
|
||||
Dns: n.Dns,
|
||||
serial: n.serial,
|
||||
Serial: n.Serial,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ func (am *DefaultAccountManager) DeletePeer(accountId string, peerKey string) (*
|
||||
RemotePeersIsEmpty: true,
|
||||
// new field
|
||||
NetworkMap: &proto.NetworkMap{
|
||||
Serial: account.Network.Serial(),
|
||||
Serial: account.Network.CurrentSerial(),
|
||||
RemotePeers: []*proto.RemotePeerConfig{},
|
||||
RemotePeersIsEmpty: true,
|
||||
},
|
||||
@@ -173,7 +173,7 @@ func (am *DefaultAccountManager) DeletePeer(accountId string, peerKey string) (*
|
||||
RemotePeersIsEmpty: len(update) == 0,
|
||||
// new field
|
||||
NetworkMap: &proto.NetworkMap{
|
||||
Serial: account.Network.Serial(),
|
||||
Serial: account.Network.CurrentSerial(),
|
||||
RemotePeers: update,
|
||||
RemotePeersIsEmpty: len(update) == 0,
|
||||
},
|
||||
|
||||
6
management/server/testdata/management.json
vendored
6
management/server/testdata/management.json
vendored
@@ -35,11 +35,11 @@
|
||||
"AuthKeysLocation": "<PASTE YOUR AUTH0 PUBLIC JWT KEYS LOCATION HERE>"
|
||||
},
|
||||
"IdpManagerConfig": {
|
||||
"Manager": "<none|auth0>",
|
||||
"ManagerType": "<none|auth0>",
|
||||
"Auth0ClientCredentials": {
|
||||
"Audience": "<PASTE YOUR AUTH0 AUDIENCE HERE>",
|
||||
"AuthIssuer": "<PASTE YOUR AUTH0 Auth Issuer HERE>",
|
||||
"ClientId": "<PASTE YOUR AUTH0 Application Client ID HERE>",
|
||||
"AuthIssuer": "https://<PASTE YOUR AUTH0 Auth Issuer HERE>",
|
||||
"ClientID": "<PASTE YOUR AUTH0 Application Client ID HERE>",
|
||||
"ClientSecret": "<PASTE YOUR AUTH0 Application Client Secret HERE>",
|
||||
"GrantType": "client_credentials"
|
||||
}
|
||||
|
||||
12
util/log.go
12
util/log.go
@@ -4,7 +4,10 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
"io"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -31,6 +34,15 @@ func InitLog(logLevel string, logPath string) error {
|
||||
logFormatter := new(log.TextFormatter)
|
||||
logFormatter.TimestampFormat = time.RFC3339 // or RFC3339
|
||||
logFormatter.FullTimestamp = true
|
||||
logFormatter.CallerPrettyfier = func(frame *runtime.Frame) (function string, file string) {
|
||||
fileName := path.Base(frame.File) + ":" + strconv.Itoa(frame.Line)
|
||||
//return frame.Function, fileName
|
||||
return "", fileName
|
||||
}
|
||||
|
||||
if level == log.DebugLevel {
|
||||
log.SetReportCaller(true)
|
||||
}
|
||||
|
||||
log.SetFormatter(logFormatter)
|
||||
log.SetLevel(level)
|
||||
|
||||
Reference in New Issue
Block a user