Config: Improve preview token security

This commit is contained in:
Michael Mayer 2021-01-02 15:08:39 +01:00
parent b716935e25
commit 51fe6cf526
4 changed files with 52 additions and 5 deletions

View file

@ -46,10 +46,10 @@ func (c *Config) InvalidPreviewToken(t string) bool {
return c.PreviewToken() != t && c.DownloadToken() != t 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 { func (c *Config) PreviewToken() string {
if c.options.PreviewToken == "" { if c.options.PreviewToken == "" {
c.options.PreviewToken = rnd.Token(8) c.options.PreviewToken = c.SerialChecksum()
} }
return c.options.PreviewToken return c.options.PreviewToken

View file

@ -1,7 +1,9 @@
package config package config
import ( import (
"encoding/hex"
"fmt" "fmt"
"hash/crc32"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -141,6 +143,10 @@ func (c *Config) Init() error {
// initStorage initializes storage directories with a random serial. // initStorage initializes storage directories with a random serial.
func (c *Config) initStorage() error { func (c *Config) initStorage() error {
if c.serial != "" {
return nil
}
const serialName = "serial" const serialName = "serial"
c.serial = rnd.PPID('z') c.serial = rnd.PPID('z')
@ -161,6 +167,28 @@ func (c *Config) initStorage() error {
return nil 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"). // Name returns the application name ("PhotoPrism").
func (c *Config) Name() string { func (c *Config) Name() string {
return c.options.Name return c.options.Name

View file

@ -304,3 +304,23 @@ func TestConfig_SiteTitle(t *testing.T) {
c.options.SiteTitle = "Cats" c.options.SiteTitle = "Cats"
assert.Equal(t, "Cats", c.SiteTitle()) 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)
}

View file

@ -295,13 +295,12 @@ var GlobalFlags = []cli.Flag{
}, },
cli.StringFlag{ cli.StringFlag{
Name: "download-token", Name: "download-token",
Usage: "`SECRET` url token for file downloads", Usage: "optional static `SECRET` url token for file downloads",
EnvVar: "PHOTOPRISM_DOWNLOAD_TOKEN", EnvVar: "PHOTOPRISM_DOWNLOAD_TOKEN",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "preview-token", Name: "preview-token",
Usage: "`SECRET` url token for preview images and video streaming", Usage: "optional static `SECRET` url token for preview images and video streaming",
Value: "public",
EnvVar: "PHOTOPRISM_PREVIEW_TOKEN", EnvVar: "PHOTOPRISM_PREVIEW_TOKEN",
}, },
cli.StringFlag{ cli.StringFlag{