From 51fe6cf5267a55074853b4b86d31066906f088c4 Mon Sep 17 00:00:00 2001 From: Michael Mayer Date: Sat, 2 Jan 2021 15:08:39 +0100 Subject: [PATCH] Config: Improve preview token security --- internal/config/auth.go | 4 ++-- internal/config/config.go | 28 ++++++++++++++++++++++++++++ internal/config/config_test.go | 20 ++++++++++++++++++++ internal/config/flags.go | 5 ++--- 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/internal/config/auth.go b/internal/config/auth.go index 9afa14608..64d6273c8 100644 --- a/internal/config/auth.go +++ b/internal/config/auth.go @@ -46,10 +46,10 @@ func (c *Config) InvalidPreviewToken(t string) bool { return c.PreviewToken() != t && c.DownloadToken() != t } -// PreviewToken returns the THUMBNAILS api token (you can optionally use a static value for permanent caching). +// PreviewToken returns the preview image api token (based on the unique storage serial by default). func (c *Config) PreviewToken() string { if c.options.PreviewToken == "" { - c.options.PreviewToken = rnd.Token(8) + c.options.PreviewToken = c.SerialChecksum() } return c.options.PreviewToken diff --git a/internal/config/config.go b/internal/config/config.go index 85a7824fb..5d5da15d9 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,7 +1,9 @@ package config import ( + "encoding/hex" "fmt" + "hash/crc32" "io/ioutil" "os" "path/filepath" @@ -141,6 +143,10 @@ func (c *Config) Init() error { // initStorage initializes storage directories with a random serial. func (c *Config) initStorage() error { + if c.serial != "" { + return nil + } + const serialName = "serial" c.serial = rnd.PPID('z') @@ -161,6 +167,28 @@ func (c *Config) initStorage() error { return nil } +// Serial returns the random storage serial. +func (c *Config) Serial() string { + if err := c.initStorage(); err != nil { + log.Errorf("config: %s", err) + } + + return c.serial +} + +// SerialChecksum returns the CRC32 checksum of the storage serial. +func (c *Config) SerialChecksum() string { + var result []byte + + hash := crc32.New(crc32.MakeTable(crc32.Castagnoli)) + + if _, err := hash.Write([]byte(c.Serial())); err != nil { + log.Warnf("config: %s", err) + } + + return hex.EncodeToString(hash.Sum(result)) +} + // Name returns the application name ("PhotoPrism"). func (c *Config) Name() string { return c.options.Name diff --git a/internal/config/config_test.go b/internal/config/config_test.go index ee3b577b9..4db2212e3 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -304,3 +304,23 @@ func TestConfig_SiteTitle(t *testing.T) { c.options.SiteTitle = "Cats" assert.Equal(t, "Cats", c.SiteTitle()) } + +func TestConfig_Serial(t *testing.T) { + c := NewConfig(CliTestContext()) + + result := c.Serial() + + t.Logf("Serial: %s", result) + + assert.NotEmpty(t, result) +} + +func TestConfig_SerialChecksum(t *testing.T) { + c := NewConfig(CliTestContext()) + + result := c.SerialChecksum() + + t.Logf("SerialChecksum: %s", result) + + assert.NotEmpty(t, result) +} diff --git a/internal/config/flags.go b/internal/config/flags.go index dbe874032..217ff2627 100644 --- a/internal/config/flags.go +++ b/internal/config/flags.go @@ -295,13 +295,12 @@ var GlobalFlags = []cli.Flag{ }, cli.StringFlag{ Name: "download-token", - Usage: "`SECRET` url token for file downloads", + Usage: "optional static `SECRET` url token for file downloads", EnvVar: "PHOTOPRISM_DOWNLOAD_TOKEN", }, cli.StringFlag{ Name: "preview-token", - Usage: "`SECRET` url token for preview images and video streaming", - Value: "public", + Usage: "optional static `SECRET` url token for preview images and video streaming", EnvVar: "PHOTOPRISM_PREVIEW_TOKEN", }, cli.StringFlag{