chore(all): memory and thread safe storage
- settings: get filter choices from storage for settings validation - updater: update servers to the storage - storage: minimal deep copying and data duplication - storage: add merged servers mutex for thread safety - connection: filter servers in storage - formatter: format servers to Markdown in storage - PIA: get server by name from storage directly - Updater: get servers count from storage directly - Updater: equality check done in storage, fix #882
This commit is contained in:
66
internal/provider/common/mocks.go
Normal file
66
internal/provider/common/mocks.go
Normal file
@@ -0,0 +1,66 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/qdm12/gluetun/internal/provider/common (interfaces: Storage)
|
||||
|
||||
// Package common is a generated GoMock package.
|
||||
package common
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
settings "github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
models "github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
// MockStorage is a mock of Storage interface.
|
||||
type MockStorage struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockStorageMockRecorder
|
||||
}
|
||||
|
||||
// MockStorageMockRecorder is the mock recorder for MockStorage.
|
||||
type MockStorageMockRecorder struct {
|
||||
mock *MockStorage
|
||||
}
|
||||
|
||||
// NewMockStorage creates a new mock instance.
|
||||
func NewMockStorage(ctrl *gomock.Controller) *MockStorage {
|
||||
mock := &MockStorage{ctrl: ctrl}
|
||||
mock.recorder = &MockStorageMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockStorage) EXPECT() *MockStorageMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// FilterServers mocks base method.
|
||||
func (m *MockStorage) FilterServers(arg0 string, arg1 settings.ServerSelection) ([]models.Server, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FilterServers", arg0, arg1)
|
||||
ret0, _ := ret[0].([]models.Server)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// FilterServers indicates an expected call of FilterServers.
|
||||
func (mr *MockStorageMockRecorder) FilterServers(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FilterServers", reflect.TypeOf((*MockStorage)(nil).FilterServers), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetServerByName mocks base method.
|
||||
func (m *MockStorage) GetServerByName(arg0, arg1 string) (models.Server, bool) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetServerByName", arg0, arg1)
|
||||
ret0, _ := ret[0].(models.Server)
|
||||
ret1, _ := ret[1].(bool)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetServerByName indicates an expected call of GetServerByName.
|
||||
func (mr *MockStorageMockRecorder) GetServerByName(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServerByName", reflect.TypeOf((*MockStorage)(nil).GetServerByName), arg0, arg1)
|
||||
}
|
||||
5
internal/provider/common/mocks_generate_test.go
Normal file
5
internal/provider/common/mocks_generate_test.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package common
|
||||
|
||||
// Exceptionally, the storage mock is exported since it is used by all
|
||||
// provider subpackages tests, and it reduces test code duplication a lot.
|
||||
//go:generate mockgen -destination=mocks.go -package $GOPACKAGE . Storage
|
||||
12
internal/provider/common/storage.go
Normal file
12
internal/provider/common/storage.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
type Storage interface {
|
||||
FilterServers(provider string, selection settings.ServerSelection) (
|
||||
servers []models.Server, err error)
|
||||
GetServerByName(provider, name string) (server models.Server, ok bool)
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package cyberghost
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(443, 443, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Cyberghost,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Cyberghost),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package expressvpn
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(0, 1195, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Expressvpn,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -1,41 +1,63 @@
|
||||
package expressvpn
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/constants/vpn"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Provider_GetConnection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const provider = providers.Expressvpn
|
||||
|
||||
errTest := errors.New("test error")
|
||||
boolPtr := func(b bool) *bool { return &b }
|
||||
|
||||
testCases := map[string]struct {
|
||||
servers []models.Server
|
||||
selection settings.ServerSelection
|
||||
connection models.Connection
|
||||
errWrapped error
|
||||
errMessage string
|
||||
filteredServers []models.Server
|
||||
storageErr error
|
||||
selection settings.ServerSelection
|
||||
connection models.Connection
|
||||
errWrapped error
|
||||
errMessage string
|
||||
panicMessage string
|
||||
}{
|
||||
"no server": {
|
||||
selection: settings.ServerSelection{}.WithDefaults(providers.Expressvpn),
|
||||
errWrapped: utils.ErrNoServer,
|
||||
errMessage: "no server",
|
||||
"error": {
|
||||
storageErr: errTest,
|
||||
errWrapped: errTest,
|
||||
errMessage: "cannot filter servers: test error",
|
||||
},
|
||||
"no filter": {
|
||||
servers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(2, 2, 2, 2)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(3, 3, 3, 3)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
"default OpenVPN TCP port": {
|
||||
filteredServers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
},
|
||||
selection: settings.ServerSelection{}.WithDefaults(providers.Expressvpn),
|
||||
selection: settings.ServerSelection{
|
||||
OpenVPN: settings.OpenVPNSelection{
|
||||
TCP: boolPtr(true),
|
||||
},
|
||||
}.WithDefaults(provider),
|
||||
panicMessage: "no default OpenVPN TCP port is defined!",
|
||||
},
|
||||
"default OpenVPN UDP port": {
|
||||
filteredServers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
},
|
||||
selection: settings.ServerSelection{
|
||||
OpenVPN: settings.OpenVPNSelection{
|
||||
TCP: boolPtr(false),
|
||||
},
|
||||
}.WithDefaults(provider),
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(1, 1, 1, 1),
|
||||
@@ -43,38 +65,14 @@ func Test_Provider_GetConnection(t *testing.T) {
|
||||
Protocol: constants.UDP,
|
||||
},
|
||||
},
|
||||
"target IP": {
|
||||
"default Wireguard port": {
|
||||
filteredServers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
},
|
||||
selection: settings.ServerSelection{
|
||||
TargetIP: net.IPv4(2, 2, 2, 2),
|
||||
}.WithDefaults(providers.Expressvpn),
|
||||
servers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(2, 2, 2, 2)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(3, 3, 3, 3)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
},
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(2, 2, 2, 2),
|
||||
Port: 1195,
|
||||
Protocol: constants.UDP,
|
||||
},
|
||||
},
|
||||
"with filter": {
|
||||
selection: settings.ServerSelection{
|
||||
Hostnames: []string{"b"},
|
||||
}.WithDefaults(providers.Expressvpn),
|
||||
servers: []models.Server{
|
||||
{Hostname: "a", IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{Hostname: "b", IPs: []net.IP{net.IPv4(2, 2, 2, 2)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{Hostname: "a", IPs: []net.IP{net.IPv4(3, 3, 3, 3)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
},
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(2, 2, 2, 2),
|
||||
Port: 1195,
|
||||
Protocol: constants.UDP,
|
||||
Hostname: "b",
|
||||
},
|
||||
VPN: vpn.Wireguard,
|
||||
}.WithDefaults(provider),
|
||||
panicMessage: "no default Wireguard port is defined!",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -82,12 +80,23 @@ func Test_Provider_GetConnection(t *testing.T) {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
storage := common.NewMockStorage(ctrl)
|
||||
storage.EXPECT().FilterServers(provider, testCase.selection).
|
||||
Return(testCase.filteredServers, testCase.storageErr)
|
||||
randSource := rand.NewSource(0)
|
||||
|
||||
m := New(testCase.servers, randSource)
|
||||
provider := New(storage, randSource)
|
||||
|
||||
connection, err := m.GetConnection(testCase.selection)
|
||||
if testCase.panicMessage != "" {
|
||||
assert.PanicsWithValue(t, testCase.panicMessage, func() {
|
||||
_, _ = provider.GetConnection(testCase.selection)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
connection, err := provider.GetConnection(testCase.selection)
|
||||
|
||||
assert.ErrorIs(t, err, testCase.errWrapped)
|
||||
if testCase.errWrapped != nil {
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Expressvpn),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package fastestvpn
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(4443, 4443, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Fastestvpn,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Fastestvpn),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package hidemyass
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(8080, 553, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.HideMyAss,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.HideMyAss),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package ipvanish
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(0, 443, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Ipvanish,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Ipvanish),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package ivpn
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(443, 1194, 58237) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Ivpn,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -1,41 +1,67 @@
|
||||
package ivpn
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/constants/vpn"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Provider_GetConnection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const provider = providers.Ivpn
|
||||
|
||||
errTest := errors.New("test error")
|
||||
boolPtr := func(b bool) *bool { return &b }
|
||||
|
||||
testCases := map[string]struct {
|
||||
servers []models.Server
|
||||
selection settings.ServerSelection
|
||||
connection models.Connection
|
||||
errWrapped error
|
||||
errMessage string
|
||||
filteredServers []models.Server
|
||||
storageErr error
|
||||
selection settings.ServerSelection
|
||||
connection models.Connection
|
||||
errWrapped error
|
||||
errMessage string
|
||||
}{
|
||||
"no server available": {
|
||||
selection: settings.ServerSelection{}.WithDefaults(providers.Ivpn),
|
||||
errWrapped: utils.ErrNoServer,
|
||||
errMessage: "no server",
|
||||
"error": {
|
||||
storageErr: errTest,
|
||||
errWrapped: errTest,
|
||||
errMessage: "cannot filter servers: test error",
|
||||
},
|
||||
"no filter": {
|
||||
servers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(2, 2, 2, 2)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(3, 3, 3, 3)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
"default OpenVPN TCP port": {
|
||||
filteredServers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
},
|
||||
selection: settings.ServerSelection{}.WithDefaults(providers.Ivpn),
|
||||
selection: settings.ServerSelection{
|
||||
OpenVPN: settings.OpenVPNSelection{
|
||||
TCP: boolPtr(true),
|
||||
},
|
||||
}.WithDefaults(provider),
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(1, 1, 1, 1),
|
||||
Port: 443,
|
||||
Protocol: constants.TCP,
|
||||
},
|
||||
},
|
||||
"default OpenVPN UDP port": {
|
||||
filteredServers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
},
|
||||
selection: settings.ServerSelection{
|
||||
OpenVPN: settings.OpenVPNSelection{
|
||||
TCP: boolPtr(false),
|
||||
},
|
||||
}.WithDefaults(provider),
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(1, 1, 1, 1),
|
||||
@@ -43,51 +69,36 @@ func Test_Provider_GetConnection(t *testing.T) {
|
||||
Protocol: constants.UDP,
|
||||
},
|
||||
},
|
||||
"target IP": {
|
||||
"default Wireguard port": {
|
||||
filteredServers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
},
|
||||
selection: settings.ServerSelection{
|
||||
TargetIP: net.IPv4(2, 2, 2, 2),
|
||||
}.WithDefaults(providers.Ivpn),
|
||||
servers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(2, 2, 2, 2)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(3, 3, 3, 3)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
},
|
||||
VPN: vpn.Wireguard,
|
||||
}.WithDefaults(provider),
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(2, 2, 2, 2),
|
||||
Port: 1194,
|
||||
Type: vpn.Wireguard,
|
||||
IP: net.IPv4(1, 1, 1, 1),
|
||||
Port: 58237,
|
||||
Protocol: constants.UDP,
|
||||
},
|
||||
},
|
||||
"with filter": {
|
||||
selection: settings.ServerSelection{
|
||||
Hostnames: []string{"b"},
|
||||
}.WithDefaults(providers.Ivpn),
|
||||
servers: []models.Server{
|
||||
{Hostname: "a", IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{Hostname: "b", IPs: []net.IP{net.IPv4(2, 2, 2, 2)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{Hostname: "a", IPs: []net.IP{net.IPv4(3, 3, 3, 3)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
},
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(2, 2, 2, 2),
|
||||
Port: 1194,
|
||||
Protocol: constants.UDP,
|
||||
Hostname: "b",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
storage := common.NewMockStorage(ctrl)
|
||||
storage.EXPECT().FilterServers(provider, testCase.selection).
|
||||
Return(testCase.filteredServers, testCase.storageErr)
|
||||
randSource := rand.NewSource(0)
|
||||
|
||||
m := New(testCase.servers, randSource)
|
||||
provider := New(storage, randSource)
|
||||
|
||||
connection, err := m.GetConnection(testCase.selection)
|
||||
connection, err := provider.GetConnection(testCase.selection)
|
||||
|
||||
assert.ErrorIs(t, err, testCase.errWrapped)
|
||||
if testCase.errWrapped != nil {
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Ivpn),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package mullvad
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(443, 1194, 51820) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Mullvad,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -1,41 +1,67 @@
|
||||
package mullvad
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/constants/vpn"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Provider_GetConnection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const provider = providers.Mullvad
|
||||
|
||||
errTest := errors.New("test error")
|
||||
boolPtr := func(b bool) *bool { return &b }
|
||||
|
||||
testCases := map[string]struct {
|
||||
servers []models.Server
|
||||
selection settings.ServerSelection
|
||||
connection models.Connection
|
||||
errWrapped error
|
||||
errMessage string
|
||||
filteredServers []models.Server
|
||||
storageErr error
|
||||
selection settings.ServerSelection
|
||||
connection models.Connection
|
||||
errWrapped error
|
||||
errMessage string
|
||||
}{
|
||||
"no server available": {
|
||||
selection: settings.ServerSelection{}.WithDefaults(providers.Mullvad),
|
||||
errWrapped: utils.ErrNoServer,
|
||||
errMessage: "no server",
|
||||
"error": {
|
||||
storageErr: errTest,
|
||||
errWrapped: errTest,
|
||||
errMessage: "cannot filter servers: test error",
|
||||
},
|
||||
"no filter": {
|
||||
servers: []models.Server{
|
||||
{VPN: vpn.OpenVPN, UDP: true, IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
{VPN: vpn.OpenVPN, UDP: true, IPs: []net.IP{net.IPv4(2, 2, 2, 2)}},
|
||||
{VPN: vpn.OpenVPN, UDP: true, IPs: []net.IP{net.IPv4(3, 3, 3, 3)}},
|
||||
"default OpenVPN TCP port": {
|
||||
filteredServers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
},
|
||||
selection: settings.ServerSelection{}.WithDefaults(providers.Mullvad),
|
||||
selection: settings.ServerSelection{
|
||||
OpenVPN: settings.OpenVPNSelection{
|
||||
TCP: boolPtr(true),
|
||||
},
|
||||
}.WithDefaults(provider),
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(1, 1, 1, 1),
|
||||
Port: 443,
|
||||
Protocol: constants.TCP,
|
||||
},
|
||||
},
|
||||
"default OpenVPN UDP port": {
|
||||
filteredServers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
},
|
||||
selection: settings.ServerSelection{
|
||||
OpenVPN: settings.OpenVPNSelection{
|
||||
TCP: boolPtr(false),
|
||||
},
|
||||
}.WithDefaults(provider),
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(1, 1, 1, 1),
|
||||
@@ -43,36 +69,17 @@ func Test_Provider_GetConnection(t *testing.T) {
|
||||
Protocol: constants.UDP,
|
||||
},
|
||||
},
|
||||
"target IP": {
|
||||
"default Wireguard port": {
|
||||
filteredServers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
},
|
||||
selection: settings.ServerSelection{
|
||||
TargetIP: net.IPv4(2, 2, 2, 2),
|
||||
}.WithDefaults(providers.Mullvad),
|
||||
servers: []models.Server{
|
||||
{VPN: vpn.OpenVPN, UDP: true, IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
{VPN: vpn.OpenVPN, UDP: true, IPs: []net.IP{net.IPv4(2, 2, 2, 2)}},
|
||||
{VPN: vpn.OpenVPN, UDP: true, IPs: []net.IP{net.IPv4(3, 3, 3, 3)}},
|
||||
},
|
||||
VPN: vpn.Wireguard,
|
||||
}.WithDefaults(provider),
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(2, 2, 2, 2),
|
||||
Port: 1194,
|
||||
Protocol: constants.UDP,
|
||||
},
|
||||
},
|
||||
"with filter": {
|
||||
selection: settings.ServerSelection{
|
||||
Hostnames: []string{"b"},
|
||||
}.WithDefaults(providers.Mullvad),
|
||||
servers: []models.Server{
|
||||
{VPN: vpn.OpenVPN, UDP: true, Hostname: "a", IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
{VPN: vpn.OpenVPN, UDP: true, Hostname: "b", IPs: []net.IP{net.IPv4(2, 2, 2, 2)}},
|
||||
{VPN: vpn.OpenVPN, UDP: true, Hostname: "a", IPs: []net.IP{net.IPv4(3, 3, 3, 3)}},
|
||||
},
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(2, 2, 2, 2),
|
||||
Port: 1194,
|
||||
Hostname: "b",
|
||||
Type: vpn.Wireguard,
|
||||
IP: net.IPv4(1, 1, 1, 1),
|
||||
Port: 51820,
|
||||
Protocol: constants.UDP,
|
||||
},
|
||||
},
|
||||
@@ -82,12 +89,16 @@ func Test_Provider_GetConnection(t *testing.T) {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
storage := common.NewMockStorage(ctrl)
|
||||
storage.EXPECT().FilterServers(provider, testCase.selection).
|
||||
Return(testCase.filteredServers, testCase.storageErr)
|
||||
randSource := rand.NewSource(0)
|
||||
|
||||
m := New(testCase.servers, randSource)
|
||||
provider := New(storage, randSource)
|
||||
|
||||
connection, err := m.GetConnection(testCase.selection)
|
||||
connection, err := provider.GetConnection(testCase.selection)
|
||||
|
||||
assert.ErrorIs(t, err, testCase.errWrapped)
|
||||
if testCase.errWrapped != nil {
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Mullvad),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package nordvpn
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(443, 1194, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Nordvpn,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Nordvpn),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package perfectprivacy
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(443, 443, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Perfectprivacy,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Perfectprivacy),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package privado
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(0, 1194, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Privado,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Privado),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package privateinternetaccess
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/privateinternetaccess/presets"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
@@ -20,5 +21,6 @@ func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
defaults.OpenVPNUDPPort = 1197
|
||||
}
|
||||
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.PrivateInternetAccess,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -15,25 +15,24 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
"github.com/qdm12/golibs/format"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrGatewayIPIsNil = errors.New("gateway IP address is nil")
|
||||
ErrServerNameEmpty = errors.New("server name is empty")
|
||||
ErrServerNameNotFound = errors.New("server name not found in servers")
|
||||
ErrGatewayIPIsNil = errors.New("gateway IP address is nil")
|
||||
ErrServerNameEmpty = errors.New("server name is empty")
|
||||
)
|
||||
|
||||
// PortForward obtains a VPN server side port forwarded from PIA.
|
||||
func (p *Provider) PortForward(ctx context.Context, client *http.Client,
|
||||
logger utils.Logger, gateway net.IP, serverName string) (
|
||||
port uint16, err error) {
|
||||
var server models.Server
|
||||
for _, server = range p.servers {
|
||||
if server.ServerName == serverName {
|
||||
break
|
||||
}
|
||||
server, ok := p.storage.GetServerByName(providers.PrivateInternetAccess, serverName)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("%w: %s", ErrServerNameNotFound, serverName)
|
||||
}
|
||||
|
||||
if !server.PortForward {
|
||||
|
||||
@@ -5,11 +5,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/openvpn"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
timeNow func() time.Time
|
||||
// Port forwarding
|
||||
@@ -17,11 +17,11 @@ type Provider struct {
|
||||
authFilePath string
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source,
|
||||
func New(storage common.Storage, randSource rand.Source,
|
||||
timeNow func() time.Time) *Provider {
|
||||
const jsonPortForwardPath = "/gluetun/piaportforward.json"
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
timeNow: timeNow,
|
||||
randSource: randSource,
|
||||
portForwardPath: jsonPortForwardPath,
|
||||
|
||||
@@ -2,6 +2,7 @@ package privatevpn
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(443, 1194, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Privatevpn,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Privatevpn),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package protonvpn
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(443, 1194, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Protonvpn,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Protonvpn),
|
||||
}
|
||||
|
||||
@@ -50,52 +50,57 @@ type PortForwarder interface {
|
||||
port uint16, gateway net.IP, serverName string) (err error)
|
||||
}
|
||||
|
||||
func New(provider string, allServers models.AllServers, timeNow func() time.Time) Provider {
|
||||
serversSlice := allServers.ServersSlice(provider)
|
||||
type Storage interface {
|
||||
FilterServers(provider string, selection settings.ServerSelection) (
|
||||
servers []models.Server, err error)
|
||||
GetServerByName(provider, name string) (server models.Server, ok bool)
|
||||
}
|
||||
|
||||
func New(provider string, storage Storage, timeNow func() time.Time) Provider {
|
||||
randSource := rand.NewSource(timeNow().UnixNano())
|
||||
switch provider {
|
||||
case providers.Custom:
|
||||
return custom.New()
|
||||
case providers.Cyberghost:
|
||||
return cyberghost.New(serversSlice, randSource)
|
||||
return cyberghost.New(storage, randSource)
|
||||
case providers.Expressvpn:
|
||||
return expressvpn.New(serversSlice, randSource)
|
||||
return expressvpn.New(storage, randSource)
|
||||
case providers.Fastestvpn:
|
||||
return fastestvpn.New(serversSlice, randSource)
|
||||
return fastestvpn.New(storage, randSource)
|
||||
case providers.HideMyAss:
|
||||
return hidemyass.New(serversSlice, randSource)
|
||||
return hidemyass.New(storage, randSource)
|
||||
case providers.Ipvanish:
|
||||
return ipvanish.New(serversSlice, randSource)
|
||||
return ipvanish.New(storage, randSource)
|
||||
case providers.Ivpn:
|
||||
return ivpn.New(serversSlice, randSource)
|
||||
return ivpn.New(storage, randSource)
|
||||
case providers.Mullvad:
|
||||
return mullvad.New(serversSlice, randSource)
|
||||
return mullvad.New(storage, randSource)
|
||||
case providers.Nordvpn:
|
||||
return nordvpn.New(serversSlice, randSource)
|
||||
return nordvpn.New(storage, randSource)
|
||||
case providers.Perfectprivacy:
|
||||
return perfectprivacy.New(serversSlice, randSource)
|
||||
return perfectprivacy.New(storage, randSource)
|
||||
case providers.Privado:
|
||||
return privado.New(serversSlice, randSource)
|
||||
return privado.New(storage, randSource)
|
||||
case providers.PrivateInternetAccess:
|
||||
return privateinternetaccess.New(serversSlice, randSource, timeNow)
|
||||
return privateinternetaccess.New(storage, randSource, timeNow)
|
||||
case providers.Privatevpn:
|
||||
return privatevpn.New(serversSlice, randSource)
|
||||
return privatevpn.New(storage, randSource)
|
||||
case providers.Protonvpn:
|
||||
return protonvpn.New(serversSlice, randSource)
|
||||
return protonvpn.New(storage, randSource)
|
||||
case providers.Purevpn:
|
||||
return purevpn.New(serversSlice, randSource)
|
||||
return purevpn.New(storage, randSource)
|
||||
case providers.Surfshark:
|
||||
return surfshark.New(serversSlice, randSource)
|
||||
return surfshark.New(storage, randSource)
|
||||
case providers.Torguard:
|
||||
return torguard.New(serversSlice, randSource)
|
||||
return torguard.New(storage, randSource)
|
||||
case providers.VPNUnlimited:
|
||||
return vpnunlimited.New(serversSlice, randSource)
|
||||
return vpnunlimited.New(storage, randSource)
|
||||
case providers.Vyprvpn:
|
||||
return vyprvpn.New(serversSlice, randSource)
|
||||
return vyprvpn.New(storage, randSource)
|
||||
case providers.Wevpn:
|
||||
return wevpn.New(serversSlice, randSource)
|
||||
return wevpn.New(storage, randSource)
|
||||
case providers.Windscribe:
|
||||
return windscribe.New(serversSlice, randSource)
|
||||
return windscribe.New(storage, randSource)
|
||||
default:
|
||||
panic("provider " + provider + " is unknown") // should never occur
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package purevpn
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(80, 53, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Purevpn,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Purevpn),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package surfshark
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(1443, 1194, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Surfshark,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Surfshark),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package torguard
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(1912, 1912, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Torguard,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Torguard),
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
@@ -24,20 +24,20 @@ func NewConnectionDefaults(openvpnTCPPort, openvpnUDPPort,
|
||||
}
|
||||
}
|
||||
|
||||
var ErrNoServer = errors.New("no server")
|
||||
type Storage interface {
|
||||
FilterServers(provider string, selection settings.ServerSelection) (
|
||||
servers []models.Server, err error)
|
||||
}
|
||||
|
||||
func GetConnection(servers []models.Server,
|
||||
func GetConnection(provider string,
|
||||
storage Storage,
|
||||
selection settings.ServerSelection,
|
||||
defaults ConnectionDefaults,
|
||||
randSource rand.Source) (
|
||||
connection models.Connection, err error) {
|
||||
if len(servers) == 0 {
|
||||
return connection, ErrNoServer
|
||||
}
|
||||
|
||||
servers = filterServers(servers, selection)
|
||||
if len(servers) == 0 {
|
||||
return connection, noServerFoundError(selection)
|
||||
servers, err := storage.FilterServers(provider, selection)
|
||||
if err != nil {
|
||||
return connection, fmt.Errorf("cannot filter servers: %w", err)
|
||||
}
|
||||
|
||||
protocol := getProtocol(selection)
|
||||
|
||||
@@ -1,23 +1,30 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/constants/vpn"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_GetConnection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
errTest := errors.New("test error")
|
||||
|
||||
testCases := map[string]struct {
|
||||
servers []models.Server
|
||||
provider string
|
||||
filteredServers []models.Server
|
||||
filterError error
|
||||
serverSelection settings.ServerSelection
|
||||
defaults ConnectionDefaults
|
||||
randSource rand.Source
|
||||
@@ -25,25 +32,13 @@ func Test_GetConnection(t *testing.T) {
|
||||
errWrapped error
|
||||
errMessage string
|
||||
}{
|
||||
"no server": {
|
||||
serverSelection: settings.ServerSelection{}.
|
||||
WithDefaults(providers.Mullvad),
|
||||
errWrapped: ErrNoServer,
|
||||
errMessage: "no server",
|
||||
},
|
||||
"all servers filtered": {
|
||||
servers: []models.Server{
|
||||
{VPN: vpn.Wireguard},
|
||||
{VPN: vpn.Wireguard},
|
||||
},
|
||||
serverSelection: settings.ServerSelection{
|
||||
VPN: vpn.OpenVPN,
|
||||
}.WithDefaults(providers.Mullvad),
|
||||
errWrapped: ErrNoServerFound,
|
||||
errMessage: "no server found: for VPN openvpn; protocol udp",
|
||||
"storage filter error": {
|
||||
filterError: errTest,
|
||||
errWrapped: errTest,
|
||||
errMessage: "cannot filter servers: test error",
|
||||
},
|
||||
"server without IPs": {
|
||||
servers: []models.Server{
|
||||
filteredServers: []models.Server{
|
||||
{VPN: vpn.OpenVPN, UDP: true},
|
||||
{VPN: vpn.OpenVPN, UDP: true},
|
||||
},
|
||||
@@ -58,7 +53,7 @@ func Test_GetConnection(t *testing.T) {
|
||||
errMessage: "no connection to pick from",
|
||||
},
|
||||
"OpenVPN server with hostname": {
|
||||
servers: []models.Server{
|
||||
filteredServers: []models.Server{
|
||||
{
|
||||
VPN: vpn.OpenVPN,
|
||||
UDP: true,
|
||||
@@ -79,7 +74,7 @@ func Test_GetConnection(t *testing.T) {
|
||||
},
|
||||
},
|
||||
"OpenVPN server with x509": {
|
||||
servers: []models.Server{
|
||||
filteredServers: []models.Server{
|
||||
{
|
||||
VPN: vpn.OpenVPN,
|
||||
UDP: true,
|
||||
@@ -101,7 +96,7 @@ func Test_GetConnection(t *testing.T) {
|
||||
},
|
||||
},
|
||||
"server with IPv4 and IPv6": {
|
||||
servers: []models.Server{
|
||||
filteredServers: []models.Server{
|
||||
{
|
||||
VPN: vpn.OpenVPN,
|
||||
UDP: true,
|
||||
@@ -128,7 +123,7 @@ func Test_GetConnection(t *testing.T) {
|
||||
},
|
||||
},
|
||||
"mixed servers": {
|
||||
servers: []models.Server{
|
||||
filteredServers: []models.Server{
|
||||
{
|
||||
VPN: vpn.OpenVPN,
|
||||
UDP: true,
|
||||
@@ -169,8 +164,14 @@ func Test_GetConnection(t *testing.T) {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
connection, err := GetConnection(testCase.servers,
|
||||
storage := common.NewMockStorage(ctrl)
|
||||
storage.EXPECT().
|
||||
FilterServers(testCase.provider, testCase.serverSelection).
|
||||
Return(testCase.filteredServers, testCase.filterError)
|
||||
|
||||
connection, err := GetConnection(testCase.provider, storage,
|
||||
testCase.serverSelection, testCase.defaults,
|
||||
testCase.randSource)
|
||||
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
)
|
||||
|
||||
func commaJoin(slice []string) string {
|
||||
return strings.Join(slice, ", ")
|
||||
}
|
||||
|
||||
var ErrNoServerFound = errors.New("no server found")
|
||||
|
||||
func noServerFoundError(selection settings.ServerSelection) (err error) {
|
||||
var messageParts []string
|
||||
|
||||
messageParts = append(messageParts, "VPN "+selection.VPN)
|
||||
|
||||
protocol := constants.UDP
|
||||
if *selection.OpenVPN.TCP {
|
||||
protocol = constants.TCP
|
||||
}
|
||||
messageParts = append(messageParts, "protocol "+protocol)
|
||||
|
||||
switch len(selection.Countries) {
|
||||
case 0:
|
||||
case 1:
|
||||
part := "country " + selection.Countries[0]
|
||||
messageParts = append(messageParts, part)
|
||||
default:
|
||||
part := "countries " + commaJoin(selection.Countries)
|
||||
messageParts = append(messageParts, part)
|
||||
}
|
||||
|
||||
switch len(selection.Regions) {
|
||||
case 0:
|
||||
case 1:
|
||||
part := "region " + selection.Regions[0]
|
||||
messageParts = append(messageParts, part)
|
||||
default:
|
||||
part := "regions " + commaJoin(selection.Regions)
|
||||
messageParts = append(messageParts, part)
|
||||
}
|
||||
|
||||
switch len(selection.Cities) {
|
||||
case 0:
|
||||
case 1:
|
||||
part := "city " + selection.Cities[0]
|
||||
messageParts = append(messageParts, part)
|
||||
default:
|
||||
part := "cities " + commaJoin(selection.Cities)
|
||||
messageParts = append(messageParts, part)
|
||||
}
|
||||
|
||||
if *selection.OwnedOnly {
|
||||
messageParts = append(messageParts, "owned servers only")
|
||||
}
|
||||
|
||||
switch len(selection.ISPs) {
|
||||
case 0:
|
||||
case 1:
|
||||
part := "ISP " + selection.ISPs[0]
|
||||
messageParts = append(messageParts, part)
|
||||
default:
|
||||
part := "ISPs " + commaJoin(selection.ISPs)
|
||||
messageParts = append(messageParts, part)
|
||||
}
|
||||
|
||||
switch len(selection.Hostnames) {
|
||||
case 0:
|
||||
case 1:
|
||||
part := "hostname " + selection.Hostnames[0]
|
||||
messageParts = append(messageParts, part)
|
||||
default:
|
||||
part := "hostnames " + commaJoin(selection.Hostnames)
|
||||
messageParts = append(messageParts, part)
|
||||
}
|
||||
|
||||
switch len(selection.Names) {
|
||||
case 0:
|
||||
case 1:
|
||||
part := "name " + selection.Names[0]
|
||||
messageParts = append(messageParts, part)
|
||||
default:
|
||||
part := "names " + commaJoin(selection.Names)
|
||||
messageParts = append(messageParts, part)
|
||||
}
|
||||
|
||||
switch len(selection.Numbers) {
|
||||
case 0:
|
||||
case 1:
|
||||
part := "server number " + strconv.Itoa(int(selection.Numbers[0]))
|
||||
messageParts = append(messageParts, part)
|
||||
default:
|
||||
serverNumbers := make([]string, len(selection.Numbers))
|
||||
for i := range selection.Numbers {
|
||||
serverNumbers[i] = strconv.Itoa(int(selection.Numbers[i]))
|
||||
}
|
||||
part := "server numbers " + commaJoin(serverNumbers)
|
||||
messageParts = append(messageParts, part)
|
||||
}
|
||||
|
||||
if *selection.OpenVPN.PIAEncPreset != "" {
|
||||
part := "encryption preset " + *selection.OpenVPN.PIAEncPreset
|
||||
messageParts = append(messageParts, part)
|
||||
}
|
||||
|
||||
if *selection.FreeOnly {
|
||||
messageParts = append(messageParts, "free tier only")
|
||||
}
|
||||
|
||||
message := "for " + strings.Join(messageParts, "; ")
|
||||
|
||||
return fmt.Errorf("%w: %s", ErrNoServerFound, message)
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package vpnunlimited
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(0, 1194, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.VPNUnlimited,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.VPNUnlimited),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package vyprvpn
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(0, 443, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Vyprvpn,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Vyprvpn),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package wevpn
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(1195, 1194, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Wevpn,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -1,43 +1,68 @@
|
||||
package wevpn
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/constants/vpn"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Provider_GetConnection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const provider = providers.Wevpn
|
||||
|
||||
errTest := errors.New("test error")
|
||||
boolPtr := func(b bool) *bool { return &b }
|
||||
|
||||
testCases := map[string]struct {
|
||||
servers []models.Server
|
||||
selection settings.ServerSelection
|
||||
connection models.Connection
|
||||
errWrapped error
|
||||
errMessage string
|
||||
filteredServers []models.Server
|
||||
storageErr error
|
||||
selection settings.ServerSelection
|
||||
connection models.Connection
|
||||
errWrapped error
|
||||
errMessage string
|
||||
panicMessage string
|
||||
}{
|
||||
"no server available": {
|
||||
selection: settings.ServerSelection{
|
||||
VPN: vpn.OpenVPN,
|
||||
}.WithDefaults(providers.Wevpn),
|
||||
errWrapped: utils.ErrNoServer,
|
||||
errMessage: "no server",
|
||||
"error": {
|
||||
storageErr: errTest,
|
||||
errWrapped: errTest,
|
||||
errMessage: "cannot filter servers: test error",
|
||||
},
|
||||
"no filter": {
|
||||
servers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(2, 2, 2, 2)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(3, 3, 3, 3)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
"default OpenVPN TCP port": {
|
||||
filteredServers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
},
|
||||
selection: settings.ServerSelection{}.WithDefaults(providers.Wevpn),
|
||||
selection: settings.ServerSelection{
|
||||
OpenVPN: settings.OpenVPNSelection{
|
||||
TCP: boolPtr(true),
|
||||
},
|
||||
}.WithDefaults(provider),
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(1, 1, 1, 1),
|
||||
Port: 1195,
|
||||
Protocol: constants.TCP,
|
||||
},
|
||||
},
|
||||
"default OpenVPN UDP port": {
|
||||
filteredServers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
},
|
||||
selection: settings.ServerSelection{
|
||||
OpenVPN: settings.OpenVPNSelection{
|
||||
TCP: boolPtr(false),
|
||||
},
|
||||
}.WithDefaults(provider),
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(1, 1, 1, 1),
|
||||
@@ -45,38 +70,14 @@ func Test_Provider_GetConnection(t *testing.T) {
|
||||
Protocol: constants.UDP,
|
||||
},
|
||||
},
|
||||
"target IP": {
|
||||
"default Wireguard port": {
|
||||
filteredServers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
},
|
||||
selection: settings.ServerSelection{
|
||||
TargetIP: net.IPv4(2, 2, 2, 2),
|
||||
}.WithDefaults(providers.Wevpn),
|
||||
servers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(2, 2, 2, 2)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(3, 3, 3, 3)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
},
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(2, 2, 2, 2),
|
||||
Port: 1194,
|
||||
Protocol: constants.UDP,
|
||||
},
|
||||
},
|
||||
"with filter": {
|
||||
selection: settings.ServerSelection{
|
||||
Hostnames: []string{"b"},
|
||||
}.WithDefaults(providers.Wevpn),
|
||||
servers: []models.Server{
|
||||
{Hostname: "a", IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{Hostname: "b", IPs: []net.IP{net.IPv4(2, 2, 2, 2)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{Hostname: "a", IPs: []net.IP{net.IPv4(3, 3, 3, 3)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
},
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(2, 2, 2, 2),
|
||||
Port: 1194,
|
||||
Hostname: "b",
|
||||
Protocol: constants.UDP,
|
||||
},
|
||||
VPN: vpn.Wireguard,
|
||||
}.WithDefaults(provider),
|
||||
panicMessage: "no default Wireguard port is defined!",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -84,12 +85,23 @@ func Test_Provider_GetConnection(t *testing.T) {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
storage := common.NewMockStorage(ctrl)
|
||||
storage.EXPECT().FilterServers(provider, testCase.selection).
|
||||
Return(testCase.filteredServers, testCase.storageErr)
|
||||
randSource := rand.NewSource(0)
|
||||
|
||||
m := New(testCase.servers, randSource)
|
||||
provider := New(storage, randSource)
|
||||
|
||||
connection, err := m.GetConnection(testCase.selection)
|
||||
if testCase.panicMessage != "" {
|
||||
assert.PanicsWithValue(t, testCase.panicMessage, func() {
|
||||
_, _ = provider.GetConnection(testCase.selection)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
connection, err := provider.GetConnection(testCase.selection)
|
||||
|
||||
assert.ErrorIs(t, err, testCase.errWrapped)
|
||||
if testCase.errWrapped != nil {
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Wevpn),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package windscribe
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
@@ -9,5 +10,6 @@ import (
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(443, 1194, 1194) //nolint:gomnd
|
||||
return utils.GetConnection(p.servers, selection, defaults, p.randSource)
|
||||
return utils.GetConnection(providers.Windscribe,
|
||||
p.storage, selection, defaults, p.randSource)
|
||||
}
|
||||
|
||||
@@ -1,41 +1,68 @@
|
||||
package windscribe
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/constants/vpn"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Provider_GetConnection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const provider = providers.Windscribe
|
||||
|
||||
errTest := errors.New("test error")
|
||||
boolPtr := func(b bool) *bool { return &b }
|
||||
|
||||
testCases := map[string]struct {
|
||||
servers []models.Server
|
||||
selection settings.ServerSelection
|
||||
connection models.Connection
|
||||
errWrapped error
|
||||
errMessage string
|
||||
filteredServers []models.Server
|
||||
storageErr error
|
||||
selection settings.ServerSelection
|
||||
connection models.Connection
|
||||
errWrapped error
|
||||
errMessage string
|
||||
panicMessage string
|
||||
}{
|
||||
"no server available": {
|
||||
selection: settings.ServerSelection{}.WithDefaults(providers.Windscribe),
|
||||
errWrapped: utils.ErrNoServer,
|
||||
errMessage: "no server",
|
||||
"error": {
|
||||
storageErr: errTest,
|
||||
errWrapped: errTest,
|
||||
errMessage: "cannot filter servers: test error",
|
||||
},
|
||||
"no filter": {
|
||||
servers: []models.Server{
|
||||
{VPN: vpn.OpenVPN, UDP: true, IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
{VPN: vpn.OpenVPN, UDP: true, IPs: []net.IP{net.IPv4(2, 2, 2, 2)}},
|
||||
{VPN: vpn.OpenVPN, UDP: true, IPs: []net.IP{net.IPv4(3, 3, 3, 3)}},
|
||||
"default OpenVPN TCP port": {
|
||||
filteredServers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
},
|
||||
selection: settings.ServerSelection{}.WithDefaults(providers.Windscribe),
|
||||
selection: settings.ServerSelection{
|
||||
OpenVPN: settings.OpenVPNSelection{
|
||||
TCP: boolPtr(true),
|
||||
},
|
||||
}.WithDefaults(provider),
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(1, 1, 1, 1),
|
||||
Port: 443,
|
||||
Protocol: constants.TCP,
|
||||
},
|
||||
},
|
||||
"default OpenVPN UDP port": {
|
||||
filteredServers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
},
|
||||
selection: settings.ServerSelection{
|
||||
OpenVPN: settings.OpenVPNSelection{
|
||||
TCP: boolPtr(false),
|
||||
},
|
||||
}.WithDefaults(provider),
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(1, 1, 1, 1),
|
||||
@@ -43,49 +70,41 @@ func Test_Provider_GetConnection(t *testing.T) {
|
||||
Protocol: constants.UDP,
|
||||
},
|
||||
},
|
||||
"target IP": {
|
||||
"default Wireguard port": {
|
||||
filteredServers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}},
|
||||
},
|
||||
selection: settings.ServerSelection{
|
||||
TargetIP: net.IPv4(2, 2, 2, 2),
|
||||
}.WithDefaults(providers.Windscribe),
|
||||
servers: []models.Server{
|
||||
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(2, 2, 2, 2)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{IPs: []net.IP{net.IPv4(3, 3, 3, 3)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
},
|
||||
VPN: vpn.Wireguard,
|
||||
}.WithDefaults(provider),
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(2, 2, 2, 2),
|
||||
Type: vpn.Wireguard,
|
||||
IP: net.IPv4(1, 1, 1, 1),
|
||||
Port: 1194,
|
||||
Protocol: constants.UDP,
|
||||
},
|
||||
},
|
||||
"with filter": {
|
||||
selection: settings.ServerSelection{
|
||||
Hostnames: []string{"b"},
|
||||
}.WithDefaults(providers.Windscribe),
|
||||
servers: []models.Server{
|
||||
{Hostname: "a", IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{Hostname: "b", IPs: []net.IP{net.IPv4(2, 2, 2, 2)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
{Hostname: "a", IPs: []net.IP{net.IPv4(3, 3, 3, 3)}, VPN: vpn.OpenVPN, UDP: true},
|
||||
},
|
||||
connection: models.Connection{
|
||||
Type: vpn.OpenVPN,
|
||||
IP: net.IPv4(2, 2, 2, 2),
|
||||
Port: 1194,
|
||||
Hostname: "b",
|
||||
Protocol: constants.UDP,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
storage := common.NewMockStorage(ctrl)
|
||||
storage.EXPECT().FilterServers(provider, testCase.selection).
|
||||
Return(testCase.filteredServers, testCase.storageErr)
|
||||
randSource := rand.NewSource(0)
|
||||
|
||||
provider := New(testCase.servers, randSource)
|
||||
provider := New(storage, randSource)
|
||||
|
||||
if testCase.panicMessage != "" {
|
||||
assert.PanicsWithValue(t, testCase.panicMessage, func() {
|
||||
_, _ = provider.GetConnection(testCase.selection)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
connection, err := provider.GetConnection(testCase.selection)
|
||||
|
||||
@@ -93,6 +112,7 @@ func Test_Provider_GetConnection(t *testing.T) {
|
||||
if testCase.errWrapped != nil {
|
||||
assert.EqualError(t, err, testCase.errMessage)
|
||||
}
|
||||
|
||||
assert.Equal(t, testCase.connection, connection)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
servers []models.Server
|
||||
storage common.Storage
|
||||
randSource rand.Source
|
||||
utils.NoPortForwarder
|
||||
}
|
||||
|
||||
func New(servers []models.Server, randSource rand.Source) *Provider {
|
||||
func New(storage common.Storage, randSource rand.Source) *Provider {
|
||||
return &Provider{
|
||||
servers: servers,
|
||||
storage: storage,
|
||||
randSource: randSource,
|
||||
NoPortForwarder: utils.NewNoPortForwarding(providers.Windscribe),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user