Auth: Refactor users path configuration and base path default
Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
parent
3755421945
commit
addc5e8251
12 changed files with 78 additions and 27 deletions
|
@ -121,6 +121,22 @@ export class User extends RestModel {
|
|||
return s[0].trim();
|
||||
}
|
||||
|
||||
defaultBasePath() {
|
||||
const handle = this.getHandle();
|
||||
|
||||
if (!handle) {
|
||||
return "";
|
||||
}
|
||||
|
||||
let dir = config.get("usersPath");
|
||||
|
||||
if (dir) {
|
||||
return `${dir}/${handle}`;
|
||||
} else {
|
||||
return `users/${handle}`;
|
||||
}
|
||||
}
|
||||
|
||||
getDisplayName() {
|
||||
if (this.DisplayName) {
|
||||
return this.DisplayName;
|
||||
|
|
|
@ -80,6 +80,7 @@ func StartImport(router *gin.RouterGroup) {
|
|||
|
||||
RemoveFromFolderCache(entity.RootImport)
|
||||
|
||||
// Get destination folder.
|
||||
var destFolder string
|
||||
if destFolder = s.User().GetUploadPath(); destFolder == "" {
|
||||
destFolder = conf.ImportDest()
|
||||
|
|
|
@ -185,6 +185,7 @@ func ProcessUserUpload(router *gin.RouterGroup) {
|
|||
|
||||
imp := get.Import()
|
||||
|
||||
// Get destination folder.
|
||||
var destFolder string
|
||||
if destFolder = s.User().GetUploadPath(); destFolder == "" {
|
||||
destFolder = conf.ImportDest()
|
||||
|
|
|
@ -60,6 +60,7 @@ type ClientConfig struct {
|
|||
UploadNSFW bool `json:"uploadNSFW"`
|
||||
Public bool `json:"public"`
|
||||
AuthMode string `json:"authMode"`
|
||||
UsersPath string `json:"usersPath"`
|
||||
LoginUri string `json:"loginUri"`
|
||||
RegisterUri string `json:"registerUri"`
|
||||
PasswordLength int `json:"passwordLength"`
|
||||
|
@ -278,6 +279,7 @@ func (c *Config) ClientPublic() ClientConfig {
|
|||
ReadOnly: c.ReadOnly(),
|
||||
Public: c.Public(),
|
||||
AuthMode: c.AuthMode(),
|
||||
UsersPath: c.UsersPath(),
|
||||
LoginUri: c.LoginUri(),
|
||||
RegisterUri: c.RegisterUri(),
|
||||
PasswordResetUri: c.PasswordResetUri(),
|
||||
|
@ -364,6 +366,7 @@ func (c *Config) ClientShare() ClientConfig {
|
|||
UploadNSFW: c.UploadNSFW(),
|
||||
Public: c.Public(),
|
||||
AuthMode: c.AuthMode(),
|
||||
UsersPath: "",
|
||||
LoginUri: c.LoginUri(),
|
||||
RegisterUri: c.RegisterUri(),
|
||||
PasswordResetUri: c.PasswordResetUri(),
|
||||
|
@ -455,6 +458,7 @@ func (c *Config) ClientUser(withSettings bool) ClientConfig {
|
|||
UploadNSFW: c.UploadNSFW(),
|
||||
Public: c.Public(),
|
||||
AuthMode: c.AuthMode(),
|
||||
UsersPath: c.UsersPath(),
|
||||
LoginUri: c.LoginUri(),
|
||||
RegisterUri: c.RegisterUri(),
|
||||
PasswordLength: c.PasswordLength(),
|
||||
|
|
|
@ -173,6 +173,9 @@ func (c *Config) Propagate() {
|
|||
// Set minimum password length.
|
||||
entity.PasswordLength = c.PasswordLength()
|
||||
|
||||
// Set path for user assets.
|
||||
entity.UsersPath = c.UsersPath()
|
||||
|
||||
// Set API preview and download default tokens.
|
||||
entity.PreviewToken.Set(c.PreviewToken(), entity.TokenConfig)
|
||||
entity.DownloadToken.Set(c.DownloadToken(), entity.TokenConfig)
|
||||
|
|
|
@ -90,8 +90,8 @@ func (c *Config) CreateDirectories() error {
|
|||
|
||||
if c.UsersPath() == "" {
|
||||
return notFoundError("users")
|
||||
} else if err := os.MkdirAll(c.UsersPath(), fs.ModeDir); err != nil {
|
||||
return createError(c.UsersPath(), err)
|
||||
} else if err := os.MkdirAll(c.UsersStoragePath(), fs.ModeDir); err != nil {
|
||||
return createError(c.UsersStoragePath(), err)
|
||||
}
|
||||
|
||||
if c.CmdCachePath() == "" {
|
||||
|
@ -325,19 +325,28 @@ func (c *Config) SidecarWritable() bool {
|
|||
return !c.ReadOnly() || c.SidecarPathIsAbs()
|
||||
}
|
||||
|
||||
// UsersPath returns the storage base path for user assets like
|
||||
// avatar images and other media that should not be indexed.
|
||||
// UsersPath returns the relative base path for user assets.
|
||||
func (c *Config) UsersPath() string {
|
||||
// Set default.
|
||||
if c.options.UsersPath == "" {
|
||||
c.options.UsersPath = filepath.Join(c.StoragePath(), "users")
|
||||
return "users"
|
||||
}
|
||||
|
||||
return c.options.UsersPath
|
||||
return clean.UserPath(c.options.UsersPath)
|
||||
}
|
||||
|
||||
// UserPath returns the storage path for user assets.
|
||||
func (c *Config) UserPath(userUid string) string {
|
||||
// UsersStoragePath returns the users storage base path.
|
||||
func (c *Config) UsersStoragePath() string {
|
||||
return filepath.Join(c.StoragePath(), c.UsersPath())
|
||||
}
|
||||
|
||||
// UsersOriginalsPath returns the users originals base path.
|
||||
func (c *Config) UsersOriginalsPath() string {
|
||||
return filepath.Join(c.OriginalsPath(), c.UsersPath())
|
||||
}
|
||||
|
||||
// UserStoragePath returns the storage path for user assets.
|
||||
func (c *Config) UserStoragePath(userUid string) string {
|
||||
if !rnd.IsUID(userUid, 0) {
|
||||
return ""
|
||||
}
|
||||
|
@ -357,7 +366,7 @@ func (c *Config) UserUploadPath(userUid, token string) (string, error) {
|
|||
return "", fmt.Errorf("invalid uid")
|
||||
}
|
||||
|
||||
dir := filepath.Join(c.UserPath(userUid), "upload", clean.Token(token))
|
||||
dir := filepath.Join(c.UserStoragePath(userUid), "upload", clean.Token(token))
|
||||
|
||||
if err := os.MkdirAll(dir, fs.ModeDir); err != nil {
|
||||
return "", err
|
||||
|
|
|
@ -25,14 +25,14 @@ func TestConfig_SidecarPath(t *testing.T) {
|
|||
|
||||
func TestConfig_UsersPath(t *testing.T) {
|
||||
c := NewConfig(CliTestContext())
|
||||
assert.Contains(t, c.UsersPath(), "testdata/users")
|
||||
assert.Contains(t, c.UsersPath(), "users")
|
||||
}
|
||||
|
||||
func TestConfig_UserPath(t *testing.T) {
|
||||
func TestConfig_UserStoragePath(t *testing.T) {
|
||||
c := NewConfig(CliTestContext())
|
||||
assert.Equal(t, "", c.UserPath(""))
|
||||
assert.Equal(t, "", c.UserPath("etaetyget"))
|
||||
assert.Contains(t, c.UserPath("urjult03ceelhw6k"), "testdata/users/urjult03ceelhw6k")
|
||||
assert.Equal(t, "", c.UserStoragePath(""))
|
||||
assert.Equal(t, "", c.UserStoragePath("etaetyget"))
|
||||
assert.Contains(t, c.UserStoragePath("urjult03ceelhw6k"), "users/urjult03ceelhw6k")
|
||||
}
|
||||
|
||||
func TestConfig_UserUploadPath(t *testing.T) {
|
||||
|
@ -50,12 +50,12 @@ func TestConfig_UserUploadPath(t *testing.T) {
|
|||
if dir, err := c.UserUploadPath("urjult03ceelhw6k", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
assert.Contains(t, dir, "testdata/users/urjult03ceelhw6k/upload")
|
||||
assert.Contains(t, dir, "users/urjult03ceelhw6k/upload")
|
||||
}
|
||||
if dir, err := c.UserUploadPath("urjult03ceelhw6k", "foo"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
assert.Contains(t, dir, "testdata/users/urjult03ceelhw6k/upload/foo")
|
||||
assert.Contains(t, dir, "users/urjult03ceelhw6k/upload/foo")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -142,11 +142,6 @@ var Flags = CliFlags{
|
|||
Usage: "custom relative or absolute sidecar `PATH` *optional*",
|
||||
EnvVar: "PHOTOPRISM_SIDECAR_PATH",
|
||||
}}, {
|
||||
Flag: cli.StringFlag{
|
||||
Name: "users-path",
|
||||
Usage: "custom users storage `PATH` *optional*",
|
||||
EnvVar: "PHOTOPRISM_USERS_PATH",
|
||||
}}, {
|
||||
Flag: cli.StringFlag{
|
||||
Name: "backup-path, ba",
|
||||
Usage: "custom backup `PATH` for index backup files *optional*",
|
||||
|
@ -167,6 +162,12 @@ var Flags = CliFlags{
|
|||
Usage: "relative originals `PATH` to which the files should be imported by default *optional*",
|
||||
EnvVar: "PHOTOPRISM_IMPORT_DEST",
|
||||
}}, {
|
||||
Flag: cli.StringFlag{
|
||||
Name: "users-path",
|
||||
Usage: "relative `PATH` to create base and upload subdirectories for users",
|
||||
EnvVar: "PHOTOPRISM_USERS_PATH",
|
||||
Value: "users",
|
||||
}}, {
|
||||
Flag: cli.StringFlag{
|
||||
Name: "assets-path, as",
|
||||
Usage: "assets `PATH` containing static resources like icons, models, and translations",
|
||||
|
|
|
@ -57,10 +57,9 @@ func (c *Config) Report() (rows [][]string, cols []string) {
|
|||
{"originals-limit", fmt.Sprintf("%d", c.OriginalsLimit())},
|
||||
{"resolution-limit", fmt.Sprintf("%d", c.ResolutionLimit())},
|
||||
|
||||
// Other paths.
|
||||
// Storage.
|
||||
{"storage-path", c.StoragePath()},
|
||||
{"sidecar-path", c.SidecarPath()},
|
||||
{"users-path", c.UsersPath()},
|
||||
{"albums-path", c.AlbumsPath()},
|
||||
{"backup-path", c.BackupPath()},
|
||||
{"cache-path", c.CachePath()},
|
||||
|
@ -69,6 +68,9 @@ func (c *Config) Report() (rows [][]string, cols []string) {
|
|||
{"thumb-cache-path", c.ThumbCachePath()},
|
||||
{"import-path", c.ImportPath()},
|
||||
{"import-dest", c.ImportDest()},
|
||||
{"users-path", c.UsersPath()},
|
||||
{"users-storage-path", c.UsersStoragePath()},
|
||||
{"users-originals-path", c.UsersOriginalsPath()},
|
||||
{"assets-path", c.AssetsPath()},
|
||||
{"static-path", c.StaticPath()},
|
||||
{"build-path", c.BuildPath()},
|
||||
|
|
|
@ -34,6 +34,9 @@ var UsernameLength = 1
|
|||
// PasswordLength specifies the minimum length of the password in characters.
|
||||
var PasswordLength = 4
|
||||
|
||||
// UsersPath is the relative path for user assets.
|
||||
var UsersPath = "users"
|
||||
|
||||
// Users represents a list of users.
|
||||
type Users []User
|
||||
|
||||
|
@ -118,6 +121,8 @@ func FindUser(find User) *User {
|
|||
stmt = stmt.Where("id = ?", find.ID)
|
||||
} else if rnd.IsUID(find.UserUID, UserUID) {
|
||||
stmt = stmt.Where("user_uid = ?", find.UserUID)
|
||||
} else if find.AuthProvider != "" && find.AuthID != "" && find.UserName != "" {
|
||||
stmt = stmt.Where("auth_provider = ? AND auth_id = ? OR user_name = ?", find.AuthProvider, find.AuthID, find.UserName)
|
||||
} else if find.UserName != "" {
|
||||
stmt = stmt.Where("user_name = ?", find.UserName)
|
||||
} else if find.UserEmail != "" {
|
||||
|
@ -432,7 +437,7 @@ func (m *User) DefaultBasePath() string {
|
|||
if s := m.Handle(); s == "" {
|
||||
return ""
|
||||
} else {
|
||||
return fmt.Sprintf("users/%s", s)
|
||||
return path.Join(UsersPath, s)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -13,11 +15,13 @@ import (
|
|||
gc "github.com/patrickmn/go-cache"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/api"
|
||||
"github.com/photoprism/photoprism/internal/config"
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
"github.com/photoprism/photoprism/internal/server/limiter"
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
)
|
||||
|
||||
// Authentication cache with an expiration time of 5 minutes.
|
||||
|
@ -38,7 +42,7 @@ func GetAuthUser(key string) *entity.User {
|
|||
}
|
||||
|
||||
// BasicAuth implements an HTTP request handler that adds basic authentication.
|
||||
func BasicAuth() gin.HandlerFunc {
|
||||
func BasicAuth(conf *config.Config) gin.HandlerFunc {
|
||||
var validate = func(c *gin.Context) (name, password, key string, valid bool) {
|
||||
name, password, key = GetCredentials(c)
|
||||
|
||||
|
@ -106,6 +110,11 @@ func BasicAuth() gin.HandlerFunc {
|
|||
// Sync disabled for this account.
|
||||
message := "sync disabled"
|
||||
|
||||
event.AuditWarn([]string{clientIp, "webdav login as %s", message}, clean.LogQuote(name))
|
||||
event.LoginError(clientIp, "webdav", name, api.UserAgent(c), message)
|
||||
} else if err = os.MkdirAll(filepath.Join(conf.OriginalsPath(), user.GetUploadPath()), fs.ModeDir); err != nil {
|
||||
message := "failed to create user upload path"
|
||||
|
||||
event.AuditWarn([]string{clientIp, "webdav login as %s", message}, clean.LogQuote(name))
|
||||
event.LoginError(clientIp, "webdav", name, api.UserAgent(c), message)
|
||||
} else {
|
||||
|
|
|
@ -31,11 +31,11 @@ func registerWebDAVRoutes(router *gin.Engine, conf *config.Config) {
|
|||
info = ""
|
||||
}
|
||||
|
||||
WebDAV(conf.OriginalsPath(), router.Group(conf.BaseUri(WebDAVOriginals), BasicAuth()), conf)
|
||||
WebDAV(conf.OriginalsPath(), router.Group(conf.BaseUri(WebDAVOriginals), BasicAuth(conf)), conf)
|
||||
log.Infof("webdav: shared %s/%s", conf.BaseUri(WebDAVOriginals), info)
|
||||
|
||||
if conf.ImportPath() != "" {
|
||||
WebDAV(conf.ImportPath(), router.Group(conf.BaseUri(WebDAVImport), BasicAuth()), conf)
|
||||
WebDAV(conf.ImportPath(), router.Group(conf.BaseUri(WebDAVImport), BasicAuth(conf)), conf)
|
||||
log.Infof("webdav: shared %s/%s", conf.BaseUri(WebDAVImport), info)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue