hotfix(storage): JSON provider versioning safety

This commit is contained in:
Quentin McGaw
2022-05-28 22:43:54 +00:00
parent 90dd3b1b5c
commit b345368257
3 changed files with 30 additions and 23 deletions

View File

@@ -1,21 +1,12 @@
package storage package storage
import ( import (
"strconv"
"time" "time"
"github.com/qdm12/gluetun/internal/constants/providers" "github.com/qdm12/gluetun/internal/constants/providers"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
) )
func (s *Storage) logVersionDiff(provider string, hardcodedVersion, persistedVersion uint16) {
message := provider + " servers from file discarded because they have version " +
strconv.Itoa(int(persistedVersion)) +
" and hardcoded servers have version " +
strconv.Itoa(int(hardcodedVersion))
s.logger.Info(message)
}
func (s *Storage) logTimeDiff(provider string, persistedUnix, hardcodedUnix int64) { func (s *Storage) logTimeDiff(provider string, persistedUnix, hardcodedUnix int64) {
diff := time.Unix(persistedUnix, 0).Sub(time.Unix(hardcodedUnix, 0)) diff := time.Unix(persistedUnix, 0).Sub(time.Unix(hardcodedUnix, 0))
if diff < 0 { if diff < 0 {

View File

@@ -2,7 +2,6 @@ package storage
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"os" "os"
@@ -78,26 +77,37 @@ func (s *Storage) extractServersFromBytes(b []byte, hardcodedVersions map[string
return servers, nil return servers, nil
} }
var (
errDecodeProvider = errors.New("cannot decode servers for provider")
)
func (s *Storage) readServers(provider string, hardcodedVersion uint16, func (s *Storage) readServers(provider string, hardcodedVersion uint16,
rawMessage json.RawMessage, titleCaser cases.Caser) (servers models.Servers, rawMessage json.RawMessage, titleCaser cases.Caser) (servers models.Servers,
versionsMatch bool, err error) { versionsMatch bool, err error) {
provider = titleCaser.String(provider) provider = titleCaser.String(provider)
var persistedServers models.Servers var versionObject struct {
err = json.Unmarshal(rawMessage, &persistedServers) Version uint16 `json:"version"`
if err != nil {
return servers, false, fmt.Errorf("%w: %s: %s", errDecodeProvider, provider, err)
} }
versionsMatch = hardcodedVersion == persistedServers.Version err = json.Unmarshal(rawMessage, &versionObject)
if err != nil {
return servers, false, fmt.Errorf("cannot decode servers version for provider %s: %w",
provider, err)
}
persistedVersion := versionObject.Version
versionsMatch = hardcodedVersion == persistedVersion
if !versionsMatch { if !versionsMatch {
s.logVersionDiff(provider, hardcodedVersion, persistedServers.Version) s.logger.Info(fmt.Sprintf(
"%s servers from file discarded because they have "+
"version %d and hardcoded servers have version %d",
provider, persistedVersion, hardcodedVersion))
return servers, versionsMatch, nil return servers, versionsMatch, nil
} }
return persistedServers, versionsMatch, nil err = json.Unmarshal(rawMessage, &servers)
if err != nil {
return servers, false, fmt.Errorf("cannot decode servers for provider %s: %w",
provider, err)
}
return servers, versionsMatch, nil
} }

View File

@@ -60,8 +60,14 @@ func Test_extractServersFromBytes(t *testing.T) {
"bad provider JSON": { "bad provider JSON": {
b: []byte(`{"cyberghost": "garbage"}`), b: []byte(`{"cyberghost": "garbage"}`),
hardcodedVersions: populateProviderToVersion(1, map[string]uint16{}), hardcodedVersions: populateProviderToVersion(1, map[string]uint16{}),
errMessage: "cannot decode servers for provider: Cyberghost: " + errMessage: "cannot decode servers version for provider Cyberghost: " +
"json: cannot unmarshal string into Go value of type models.Servers", "json: cannot unmarshal string into Go value of type struct { Version uint16 \"json:\\\"version\\\"\" }",
},
"bad servers array JSON": {
b: []byte(`{"cyberghost": {"version": 1, "servers": "garbage"}}`),
hardcodedVersions: populateProviderToVersion(1, map[string]uint16{}),
errMessage: "cannot decode servers for provider Cyberghost: " +
"json: cannot unmarshal string into Go struct field Servers.servers of type []models.Server",
}, },
"absent provider keys": { "absent provider keys": {
b: []byte(`{}`), b: []byte(`{}`),