Files
gluetun/internal/storage/read.go
Quentin McGaw ac9571c6b2 chore(storage): runtime defaults on servers data
- `openvpn` default VPN protocol for servers
- True UDP if VPN protocol is Wireguard
2022-04-18 12:08:26 +00:00

288 lines
8.6 KiB
Go

package storage
import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
"strings"
"github.com/qdm12/gluetun/internal/constants/providers"
"github.com/qdm12/gluetun/internal/models"
)
// 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) {
file, err := os.Open(filepath)
if os.IsNotExist(err) {
return servers, nil
} else if err != nil {
return servers, err
}
b, err := io.ReadAll(file)
if err != nil {
return servers, err
}
if err := file.Close(); err != nil {
return servers, err
}
return s.extractServersFromBytes(b, hardcoded)
}
func (s *Storage) extractServersFromBytes(b []byte, hardcoded models.AllServers) (
servers models.AllServers, err error) {
var versions allVersions
if err := json.Unmarshal(b, &versions); err != nil {
return servers, fmt.Errorf("cannot decode versions: %w", err)
}
var rawMessages allJSONRawMessages
if err := json.Unmarshal(b, &rawMessages); err != nil {
return servers, fmt.Errorf("cannot decode servers: %w", err)
}
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
}
element.target.SetDefaults()
}
return servers, nil
}
var (
errDecodeProvider = errors.New("cannot decode servers for provider")
)
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
}
err = json.Unmarshal(rawMessage, &servers)
if err != nil {
return servers, fmt.Errorf("%w: %s: %s", errDecodeProvider, provider, err)
}
return servers, nil
}
// allVersions is a subset of models.AllServers structure used to track
// versions to avoid unmarshaling errors.
type allVersions struct {
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"`
}
type serverVersion struct {
Version uint16 `json:"version"`
}
// allJSONRawMessages is to delay decoding of each provider servers.
type allJSONRawMessages struct {
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"`
}