2021-08-27 19:10:03 +00:00
|
|
|
package storage
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
2021-09-30 15:22:57 +00:00
|
|
|
"fmt"
|
2021-08-27 19:10:03 +00:00
|
|
|
"io"
|
|
|
|
|
"os"
|
2022-04-18 09:00:02 +00:00
|
|
|
"strings"
|
2021-08-27 19:10:03 +00:00
|
|
|
|
2022-04-18 09:00:02 +00:00
|
|
|
"github.com/qdm12/gluetun/internal/constants/providers"
|
2021-08-27 19:10:03 +00:00
|
|
|
"github.com/qdm12/gluetun/internal/models"
|
|
|
|
|
)
|
|
|
|
|
|
2021-09-30 15:22:57 +00:00
|
|
|
// readFromFile reads the servers from server.json.
|
|
|
|
|
// It only reads servers that have the same version as the hardcoded servers version
|
|
|
|
|
// to avoid JSON unmarshaling errors.
|
|
|
|
|
func (s *Storage) readFromFile(filepath string, hardcoded models.AllServers) (
|
|
|
|
|
servers models.AllServers, err error) {
|
2021-08-27 19:10:03 +00:00
|
|
|
file, err := os.Open(filepath)
|
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
|
return servers, nil
|
|
|
|
|
} else if err != nil {
|
|
|
|
|
return servers, err
|
|
|
|
|
}
|
2021-09-30 15:22:57 +00:00
|
|
|
|
|
|
|
|
b, err := io.ReadAll(file)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return servers, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := file.Close(); err != nil {
|
2021-08-27 19:10:03 +00:00
|
|
|
return servers, err
|
|
|
|
|
}
|
2021-09-30 15:22:57 +00:00
|
|
|
|
|
|
|
|
return s.extractServersFromBytes(b, hardcoded)
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-18 09:00:02 +00:00
|
|
|
func (s *Storage) extractServersFromBytes(b []byte, hardcoded models.AllServers) (
|
2021-09-30 15:22:57 +00:00
|
|
|
servers models.AllServers, err error) {
|
|
|
|
|
var versions allVersions
|
|
|
|
|
if err := json.Unmarshal(b, &versions); err != nil {
|
2022-02-20 02:58:16 +00:00
|
|
|
return servers, fmt.Errorf("cannot decode versions: %w", err)
|
2021-09-30 15:22:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var rawMessages allJSONRawMessages
|
|
|
|
|
if err := json.Unmarshal(b, &rawMessages); err != nil {
|
2022-02-20 02:58:16 +00:00
|
|
|
return servers, fmt.Errorf("cannot decode servers: %w", err)
|
2021-09-30 15:22:57 +00:00
|
|
|
}
|
|
|
|
|
|
2022-04-18 09:00:02 +00:00
|
|
|
type element struct {
|
|
|
|
|
provider string
|
|
|
|
|
hardcoded models.Servers
|
|
|
|
|
serverVersion serverVersion
|
|
|
|
|
rawMessage json.RawMessage
|
|
|
|
|
target *models.Servers
|
|
|
|
|
}
|
|
|
|
|
elements := []element{
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Cyberghost,
|
|
|
|
|
hardcoded: hardcoded.Cyberghost,
|
|
|
|
|
serverVersion: versions.Cyberghost,
|
|
|
|
|
rawMessage: rawMessages.Cyberghost,
|
|
|
|
|
target: &servers.Cyberghost,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Expressvpn,
|
|
|
|
|
hardcoded: hardcoded.Expressvpn,
|
|
|
|
|
serverVersion: versions.Expressvpn,
|
|
|
|
|
rawMessage: rawMessages.Expressvpn,
|
|
|
|
|
target: &servers.Expressvpn,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Fastestvpn,
|
|
|
|
|
hardcoded: hardcoded.Fastestvpn,
|
|
|
|
|
serverVersion: versions.Fastestvpn,
|
|
|
|
|
rawMessage: rawMessages.Fastestvpn,
|
|
|
|
|
target: &servers.Fastestvpn,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.HideMyAss,
|
|
|
|
|
hardcoded: hardcoded.HideMyAss,
|
|
|
|
|
serverVersion: versions.HideMyAss,
|
|
|
|
|
rawMessage: rawMessages.HideMyAss,
|
|
|
|
|
target: &servers.HideMyAss,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Ipvanish,
|
|
|
|
|
hardcoded: hardcoded.Ipvanish,
|
|
|
|
|
serverVersion: versions.Ipvanish,
|
|
|
|
|
rawMessage: rawMessages.Ipvanish,
|
|
|
|
|
target: &servers.Ipvanish,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Ivpn,
|
|
|
|
|
hardcoded: hardcoded.Ivpn,
|
|
|
|
|
serverVersion: versions.Ivpn,
|
|
|
|
|
rawMessage: rawMessages.Ivpn,
|
|
|
|
|
target: &servers.Ivpn,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Mullvad,
|
|
|
|
|
hardcoded: hardcoded.Mullvad,
|
|
|
|
|
serverVersion: versions.Mullvad,
|
|
|
|
|
rawMessage: rawMessages.Mullvad,
|
|
|
|
|
target: &servers.Mullvad,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Nordvpn,
|
|
|
|
|
hardcoded: hardcoded.Nordvpn,
|
|
|
|
|
serverVersion: versions.Nordvpn,
|
|
|
|
|
rawMessage: rawMessages.Nordvpn,
|
|
|
|
|
target: &servers.Nordvpn,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Perfectprivacy,
|
|
|
|
|
hardcoded: hardcoded.Perfectprivacy,
|
|
|
|
|
serverVersion: versions.Perfectprivacy,
|
|
|
|
|
rawMessage: rawMessages.Perfectprivacy,
|
|
|
|
|
target: &servers.Perfectprivacy,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Privado,
|
|
|
|
|
hardcoded: hardcoded.Privado,
|
|
|
|
|
serverVersion: versions.Privado,
|
|
|
|
|
rawMessage: rawMessages.Privado,
|
|
|
|
|
target: &servers.Privado,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.PrivateInternetAccess,
|
|
|
|
|
hardcoded: hardcoded.Pia,
|
|
|
|
|
serverVersion: versions.Pia,
|
|
|
|
|
rawMessage: rawMessages.Pia,
|
|
|
|
|
target: &servers.Pia,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Privatevpn,
|
|
|
|
|
hardcoded: hardcoded.Privatevpn,
|
|
|
|
|
serverVersion: versions.Privatevpn,
|
|
|
|
|
rawMessage: rawMessages.Privatevpn,
|
|
|
|
|
target: &servers.Privatevpn,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Protonvpn,
|
|
|
|
|
hardcoded: hardcoded.Protonvpn,
|
|
|
|
|
serverVersion: versions.Protonvpn,
|
|
|
|
|
rawMessage: rawMessages.Protonvpn,
|
|
|
|
|
target: &servers.Protonvpn,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Purevpn,
|
|
|
|
|
hardcoded: hardcoded.Purevpn,
|
|
|
|
|
serverVersion: versions.Purevpn,
|
|
|
|
|
rawMessage: rawMessages.Purevpn,
|
|
|
|
|
target: &servers.Purevpn,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Surfshark,
|
|
|
|
|
hardcoded: hardcoded.Surfshark,
|
|
|
|
|
serverVersion: versions.Surfshark,
|
|
|
|
|
rawMessage: rawMessages.Surfshark,
|
|
|
|
|
target: &servers.Surfshark,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Torguard,
|
|
|
|
|
hardcoded: hardcoded.Torguard,
|
|
|
|
|
serverVersion: versions.Torguard,
|
|
|
|
|
rawMessage: rawMessages.Torguard,
|
|
|
|
|
target: &servers.Torguard,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.VPNUnlimited,
|
|
|
|
|
hardcoded: hardcoded.VPNUnlimited,
|
|
|
|
|
serverVersion: versions.VPNUnlimited,
|
|
|
|
|
rawMessage: rawMessages.VPNUnlimited,
|
|
|
|
|
target: &servers.VPNUnlimited,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Vyprvpn,
|
|
|
|
|
hardcoded: hardcoded.Vyprvpn,
|
|
|
|
|
serverVersion: versions.Vyprvpn,
|
|
|
|
|
rawMessage: rawMessages.Vyprvpn,
|
|
|
|
|
target: &servers.Vyprvpn,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Wevpn,
|
|
|
|
|
hardcoded: hardcoded.Wevpn,
|
|
|
|
|
serverVersion: versions.Wevpn,
|
|
|
|
|
rawMessage: rawMessages.Wevpn,
|
|
|
|
|
target: &servers.Wevpn,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
provider: providers.Windscribe,
|
|
|
|
|
hardcoded: hardcoded.Windscribe,
|
|
|
|
|
serverVersion: versions.Windscribe,
|
|
|
|
|
rawMessage: rawMessages.Windscribe,
|
|
|
|
|
target: &servers.Windscribe,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, element := range elements {
|
|
|
|
|
*element.target, err = s.readServers(element.provider,
|
|
|
|
|
element.hardcoded, element.serverVersion, element.rawMessage)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return servers, err
|
2021-09-30 15:22:57 +00:00
|
|
|
}
|
2022-04-18 11:59:15 +00:00
|
|
|
element.target.SetDefaults()
|
2021-09-30 15:22:57 +00:00
|
|
|
}
|
|
|
|
|
|
2022-04-18 09:00:02 +00:00
|
|
|
return servers, nil
|
|
|
|
|
}
|
2021-09-30 15:22:57 +00:00
|
|
|
|
2022-04-18 09:00:02 +00:00
|
|
|
var (
|
|
|
|
|
errDecodeProvider = errors.New("cannot decode servers for provider")
|
|
|
|
|
)
|
2021-09-30 15:22:57 +00:00
|
|
|
|
2022-04-18 09:00:02 +00:00
|
|
|
func (s *Storage) readServers(provider string, hardcoded models.Servers,
|
|
|
|
|
serverVersion serverVersion, rawMessage json.RawMessage) (
|
|
|
|
|
servers models.Servers, err error) {
|
|
|
|
|
provider = strings.Title(provider)
|
|
|
|
|
if hardcoded.Version != serverVersion.Version {
|
|
|
|
|
s.logVersionDiff(provider, hardcoded.Version, serverVersion.Version)
|
|
|
|
|
return servers, nil
|
2021-09-30 15:22:57 +00:00
|
|
|
}
|
|
|
|
|
|
2022-04-18 09:00:02 +00:00
|
|
|
err = json.Unmarshal(rawMessage, &servers)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return servers, fmt.Errorf("%w: %s: %s", errDecodeProvider, provider, err)
|
2021-09-30 15:22:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return servers, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// allVersions is a subset of models.AllServers structure used to track
|
|
|
|
|
// versions to avoid unmarshaling errors.
|
|
|
|
|
type allVersions struct {
|
2021-10-05 10:44:15 -07:00
|
|
|
Version uint16 `json:"version"` // used for migration of the top level scheme
|
|
|
|
|
Cyberghost serverVersion `json:"cyberghost"`
|
|
|
|
|
Expressvpn serverVersion `json:"expressvpn"`
|
|
|
|
|
Fastestvpn serverVersion `json:"fastestvpn"`
|
|
|
|
|
HideMyAss serverVersion `json:"hidemyass"`
|
|
|
|
|
Ipvanish serverVersion `json:"ipvanish"`
|
|
|
|
|
Ivpn serverVersion `json:"ivpn"`
|
|
|
|
|
Mullvad serverVersion `json:"mullvad"`
|
|
|
|
|
Nordvpn serverVersion `json:"nordvpn"`
|
|
|
|
|
Perfectprivacy serverVersion `json:"perfectprivacy"`
|
|
|
|
|
Privado serverVersion `json:"privado"`
|
|
|
|
|
Pia serverVersion `json:"pia"`
|
|
|
|
|
Privatevpn serverVersion `json:"privatevpn"`
|
|
|
|
|
Protonvpn serverVersion `json:"protonvpn"`
|
|
|
|
|
Purevpn serverVersion `json:"purevpn"`
|
|
|
|
|
Surfshark serverVersion `json:"surfshark"`
|
|
|
|
|
Torguard serverVersion `json:"torguard"`
|
|
|
|
|
VPNUnlimited serverVersion `json:"vpnunlimited"`
|
|
|
|
|
Vyprvpn serverVersion `json:"vyprvpn"`
|
|
|
|
|
Wevpn serverVersion `json:"wevpn"`
|
|
|
|
|
Windscribe serverVersion `json:"windscribe"`
|
2021-09-30 15:22:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type serverVersion struct {
|
|
|
|
|
Version uint16 `json:"version"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// allJSONRawMessages is to delay decoding of each provider servers.
|
|
|
|
|
type allJSONRawMessages struct {
|
2021-10-05 10:44:15 -07:00
|
|
|
Version uint16 `json:"version"` // used for migration of the top level scheme
|
|
|
|
|
Cyberghost json.RawMessage `json:"cyberghost"`
|
|
|
|
|
Expressvpn json.RawMessage `json:"expressvpn"`
|
|
|
|
|
Fastestvpn json.RawMessage `json:"fastestvpn"`
|
|
|
|
|
HideMyAss json.RawMessage `json:"hidemyass"`
|
|
|
|
|
Ipvanish json.RawMessage `json:"ipvanish"`
|
|
|
|
|
Ivpn json.RawMessage `json:"ivpn"`
|
|
|
|
|
Mullvad json.RawMessage `json:"mullvad"`
|
|
|
|
|
Nordvpn json.RawMessage `json:"nordvpn"`
|
|
|
|
|
Perfectprivacy json.RawMessage `json:"perfectprivacy"`
|
|
|
|
|
Privado json.RawMessage `json:"privado"`
|
|
|
|
|
Pia json.RawMessage `json:"pia"`
|
|
|
|
|
Privatevpn json.RawMessage `json:"privatevpn"`
|
|
|
|
|
Protonvpn json.RawMessage `json:"protonvpn"`
|
|
|
|
|
Purevpn json.RawMessage `json:"purevpn"`
|
|
|
|
|
Surfshark json.RawMessage `json:"surfshark"`
|
|
|
|
|
Torguard json.RawMessage `json:"torguard"`
|
|
|
|
|
VPNUnlimited json.RawMessage `json:"vpnunlimited"`
|
|
|
|
|
Vyprvpn json.RawMessage `json:"vyprvpn"`
|
|
|
|
|
Wevpn json.RawMessage `json:"wevpn"`
|
|
|
|
|
Windscribe json.RawMessage `json:"windscribe"`
|
2021-08-27 19:10:03 +00:00
|
|
|
}
|