Config: Initialize storage folder with serial

To detect non-permanent storage and configuration issues.

Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
Michael Mayer 2020-12-05 06:21:16 +01:00
parent 7d41857bbd
commit 5acc02e248
7 changed files with 55 additions and 18 deletions

View file

@ -2,6 +2,9 @@ package config
import ( import (
"fmt" "fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime" "runtime"
"strings" "strings"
"sync" "sync"
@ -33,6 +36,7 @@ type Config struct {
settings *Settings settings *Settings
hub *hub.Config hub *hub.Config
token string token string
serial string
} }
func init() { func init() {
@ -95,6 +99,10 @@ func (c *Config) Init() error {
return err return err
} }
if err := c.initStorage(); err != nil {
return err
}
c.initSettings() c.initSettings()
c.initHub() c.initHub()
@ -103,6 +111,28 @@ func (c *Config) Init() error {
return c.connectDb() return c.connectDb()
} }
// initStorage initializes storage directories with a random serial.
func (c *Config) initStorage() error {
const serialName = "serial"
c.serial = rnd.PPID('z')
storageName := filepath.Join(c.StoragePath(), serialName)
backupName := filepath.Join(c.BackupPath(), serialName)
if data, err := ioutil.ReadFile(storageName); err == nil {
c.serial = string(data)
} else if data, err := ioutil.ReadFile(backupName); err == nil {
c.serial = string(data)
} else if err := ioutil.WriteFile(storageName, []byte(c.serial), os.ModePerm); err != nil {
return fmt.Errorf("failed creating %s: %s", storageName, err)
} else if err := ioutil.WriteFile(backupName, []byte(c.serial), os.ModePerm); err != nil {
return fmt.Errorf("failed creating %s: %s", backupName, err)
}
return nil
}
// Name returns the application name ("PhotoPrism"). // Name returns the application name ("PhotoPrism").
func (c *Config) Name() string { func (c *Config) Name() string {
return c.params.Name return c.params.Name
@ -294,7 +324,7 @@ func (c *Config) UpdateHub() {
// initHub initializes PhotoPrism hub config. // initHub initializes PhotoPrism hub config.
func (c *Config) initHub() { func (c *Config) initHub() {
c.hub = hub.NewConfig(c.Version(), c.HubConfigFile()) c.hub = hub.NewConfig(c.Version(), c.HubConfigFile(), c.serial)
if err := c.hub.Load(); err == nil { if err := c.hub.Load(); err == nil {
// Do nothing. // Do nothing.

View file

@ -30,17 +30,19 @@ type Config struct {
Session string `json:"session" yaml:"session"` Session string `json:"session" yaml:"session"`
Status string `json:"status" yaml:"status"` Status string `json:"status" yaml:"status"`
Version string `json:"version" yaml:"version"` Version string `json:"version" yaml:"version"`
Serial string `json:"serial" yaml:"serial"`
FileName string `json:"-" yaml:"-"` FileName string `json:"-" yaml:"-"`
} }
// NewConfig creates a new backend api credentials instance. // NewConfig creates a new backend api credentials instance.
func NewConfig(version string, fileName string) *Config { func NewConfig(version, fileName, serial string) *Config {
return &Config{ return &Config{
Key: "", Key: "",
Secret: "", Secret: "",
Session: "", Session: "",
Status: "", Status: "",
Version: version, Version: version,
Serial: serial,
FileName: fileName, FileName: fileName,
} }
} }
@ -140,7 +142,7 @@ func (c *Config) Refresh() (err error) {
log.Debugf("requesting api key for maps & places from %s", ApiHost()) log.Debugf("requesting api key for maps & places from %s", ApiHost())
} }
if j, err := json.Marshal(NewRequest(c.Version)); err != nil { if j, err := json.Marshal(NewRequest(c.Version, c.Serial)); err != nil {
return err return err
} else if req, err = http.NewRequest(method, url, bytes.NewReader(j)); err != nil { } else if req, err = http.NewRequest(method, url, bytes.NewReader(j)); err != nil {
return err return err

View file

@ -8,7 +8,7 @@ import (
func TestConfig_MapKey(t *testing.T) { func TestConfig_MapKey(t *testing.T) {
t.Run("success", func(t *testing.T) { t.Run("success", func(t *testing.T) {
c := NewConfig("0.0.0", "testdata/new.yml") c := NewConfig("0.0.0", "testdata/new.yml", "zqkunt22r0bewti9")
assert.Equal(t, "", c.MapKey()) assert.Equal(t, "", c.MapKey())
}) })
} }

View file

@ -23,15 +23,17 @@ type Feedback struct {
UserAgent string `json:"UserAgent"` UserAgent string `json:"UserAgent"`
ApiKey string `json:"ApiKey"` ApiKey string `json:"ApiKey"`
ClientVersion string `json:"ClientVersion"` ClientVersion string `json:"ClientVersion"`
ClientSerial string `json:"ClientSerial"`
ClientOS string `json:"ClientOS"` ClientOS string `json:"ClientOS"`
ClientArch string `json:"ClientArch"` ClientArch string `json:"ClientArch"`
ClientCPU int `json:"ClientCPU"` ClientCPU int `json:"ClientCPU"`
} }
// NewFeedback creates a new hub feedback instance. // NewFeedback creates a new hub feedback instance.
func NewFeedback(version string) *Feedback { func NewFeedback(version, serial string) *Feedback {
return &Feedback{ return &Feedback{
ClientVersion: version, ClientVersion: version,
ClientSerial: serial,
ClientOS: runtime.GOOS, ClientOS: runtime.GOOS,
ClientArch: runtime.GOARCH, ClientArch: runtime.GOARCH,
ClientCPU: runtime.NumCPU(), ClientCPU: runtime.NumCPU(),
@ -39,7 +41,7 @@ func NewFeedback(version string) *Feedback {
} }
func (c *Config) SendFeedback(f form.Feedback) (err error) { func (c *Config) SendFeedback(f form.Feedback) (err error) {
feedback := NewFeedback(c.Version) feedback := NewFeedback(c.Version, c.Serial)
feedback.Category = f.Category feedback.Category = f.Category
feedback.Subject = txt.TrimLen(f.Message, 50) feedback.Subject = txt.TrimLen(f.Message, 50)
feedback.Message = f.Message feedback.Message = f.Message

View file

@ -9,14 +9,15 @@ import (
func TestNewFeedback(t *testing.T) { func TestNewFeedback(t *testing.T) {
t.Run("success", func(t *testing.T) { t.Run("success", func(t *testing.T) {
feedback := NewFeedback("xxx") feedback := NewFeedback("xxx", "zqkunt22r0bewti9")
assert.Equal(t, "xxx", feedback.ClientVersion) assert.Equal(t, "xxx", feedback.ClientVersion)
assert.Equal(t, "zqkunt22r0bewti9", feedback.ClientSerial)
}) })
} }
func TestSendFeedback(t *testing.T) { func TestSendFeedback(t *testing.T) {
t.Run("success", func(t *testing.T) { t.Run("success", func(t *testing.T) {
c := NewConfig("0.0.0", "testdata/new.yml") c := NewConfig("0.0.0", "testdata/new.yml", "zqkunt22r0bewti9")
feedback := Feedback{ feedback := Feedback{
Category: "Bug Report", Category: "Bug Report",

View file

@ -49,13 +49,13 @@ func Token(size uint) string {
} }
func TestNewConfig(t *testing.T) { func TestNewConfig(t *testing.T) {
c := NewConfig("0.0.0", "testdata/new.yml") c := NewConfig("0.0.0", "testdata/new.yml", "zqkunt22r0bewti9")
assert.IsType(t, &Config{}, c) assert.IsType(t, &Config{}, c)
} }
func TestNewRequest(t *testing.T) { func TestNewRequest(t *testing.T) {
r := NewRequest("0.0.0") r := NewRequest("0.0.0", "zqkunt22r0bewti9")
assert.IsType(t, &Request{}, r) assert.IsType(t, &Request{}, r)
@ -72,7 +72,7 @@ func TestConfig_Refresh(t *testing.T) {
t.Run("success", func(t *testing.T) { t.Run("success", func(t *testing.T) {
fileName := fmt.Sprintf("testdata/hub.%s.yml", Token(8)) fileName := fmt.Sprintf("testdata/hub.%s.yml", Token(8))
c := NewConfig("0.0.0", fileName) c := NewConfig("0.0.0", fileName, "zqkunt22r0bewti9")
if err := c.Refresh(); err != nil { if err := c.Refresh(); err != nil {
t.Fatal(err) t.Fatal(err)
@ -122,7 +122,7 @@ func TestConfig_Refresh(t *testing.T) {
func TestConfig_DecodeSession(t *testing.T) { func TestConfig_DecodeSession(t *testing.T) {
t.Run("hub3.yml", func(t *testing.T) { t.Run("hub3.yml", func(t *testing.T) {
c := NewConfig("0.0.0", "testdata/hub3.yml") c := NewConfig("0.0.0", "testdata/hub3.yml", "zqkunt22r0bewti9")
err := c.Load() err := c.Load()
@ -138,7 +138,7 @@ func TestConfig_DecodeSession(t *testing.T) {
func TestConfig_Load(t *testing.T) { func TestConfig_Load(t *testing.T) {
t.Run("hub1.yml", func(t *testing.T) { t.Run("hub1.yml", func(t *testing.T) {
c := NewConfig("0.0.0", "testdata/hub1.yml") c := NewConfig("0.0.0", "testdata/hub1.yml", "zqkunt22r0bewti9")
if err := c.Load(); err != nil { if err := c.Load(); err != nil {
t.Logf(err.Error()) t.Logf(err.Error())
@ -151,7 +151,7 @@ func TestConfig_Load(t *testing.T) {
assert.Equal(t, "0.0.0", c.Version) assert.Equal(t, "0.0.0", c.Version)
}) })
t.Run("hub2.yml", func(t *testing.T) { t.Run("hub2.yml", func(t *testing.T) {
c := NewConfig("0.0.0", "testdata/hub2.yml") c := NewConfig("0.0.0", "testdata/hub2.yml", "zqkunt22r0bewti9")
if err := c.Load(); err != nil { if err := c.Load(); err != nil {
t.Logf(err.Error()) t.Logf(err.Error())
@ -164,7 +164,7 @@ func TestConfig_Load(t *testing.T) {
assert.Equal(t, "200925-f8e2b580-Darwin-i386-DEBUG", c.Version) assert.Equal(t, "200925-f8e2b580-Darwin-i386-DEBUG", c.Version)
}) })
t.Run("not existing filename", func(t *testing.T) { t.Run("not existing filename", func(t *testing.T) {
c := NewConfig("0.0.0", "testdata/hub_xxx.yml") c := NewConfig("0.0.0", "testdata/hub_xxx.yml", "zqkunt22r0bewti9")
if err := c.Load(); err == nil { if err := c.Load(); err == nil {
t.Fatal("file should not exist") t.Fatal("file should not exist")
@ -180,7 +180,7 @@ func TestConfig_Save(t *testing.T) {
t.Run("existing filename", func(t *testing.T) { t.Run("existing filename", func(t *testing.T) {
assert.FileExists(t, "testdata/hub1.yml") assert.FileExists(t, "testdata/hub1.yml")
c := NewConfig("0.0.0", "testdata/hub1.yml") c := NewConfig("0.0.0", "testdata/hub1.yml", "zqkunt22r0bewti9")
if err := c.Load(); err != nil { if err := c.Load(); err != nil {
t.Logf(err.Error()) t.Logf(err.Error())
@ -219,7 +219,7 @@ func TestConfig_Save(t *testing.T) {
assert.Equal(t, "0.0.0", c.Version) assert.Equal(t, "0.0.0", c.Version)
}) })
t.Run("not existing filename", func(t *testing.T) { t.Run("not existing filename", func(t *testing.T) {
c := NewConfig("0.0.0", "testdata/hub_new.yml") c := NewConfig("0.0.0", "testdata/hub_new.yml", "zqkunt22r0bewti9")
c.Key = "F60F5B25D59C397989E3CD374F81CDD7710A4FCA" c.Key = "F60F5B25D59C397989E3CD374F81CDD7710A4FCA"
c.Secret = "foo" c.Secret = "foo"
c.Session = "bar" c.Session = "bar"

View file

@ -10,15 +10,17 @@ var ServiceURL = "https://hub.photoprism.app/v1/hello"
// Backend api credentials request incl basic runtime specs. // Backend api credentials request incl basic runtime specs.
type Request struct { type Request struct {
ClientVersion string `json:"ClientVersion"` ClientVersion string `json:"ClientVersion"`
ClientSerial string `json:"ClientSerial"`
ClientOS string `json:"ClientOS"` ClientOS string `json:"ClientOS"`
ClientArch string `json:"ClientArch"` ClientArch string `json:"ClientArch"`
ClientCPU int `json:"ClientCPU"` ClientCPU int `json:"ClientCPU"`
} }
// NewRequest creates a new hub key request instance. // NewRequest creates a new hub key request instance.
func NewRequest(version string) *Request { func NewRequest(version, serial string) *Request {
return &Request{ return &Request{
ClientVersion: version, ClientVersion: version,
ClientSerial: serial,
ClientOS: runtime.GOOS, ClientOS: runtime.GOOS,
ClientArch: runtime.GOARCH, ClientArch: runtime.GOARCH,
ClientCPU: runtime.NumCPU(), ClientCPU: runtime.NumCPU(),