diff --git a/Makefile b/Makefile index a822e1ff8..740822d66 100644 --- a/Makefile +++ b/Makefile @@ -94,6 +94,7 @@ install: [ ! -f "$(GOBIN)/exif-read-tool" ] || cp $(GOBIN)/exif-read-tool $(DESTDIR)/bin/exif-read-tool rsync -r -l --safe-links --exclude-from=assets/.buildignore --chmod=a+r,u+rw ./assets/ $(DESTDIR)/assets wget -O $(DESTDIR)/assets/static/img/wallpaper/welcome.jpg https://cdn.photoprism.app/wallpaper/welcome.jpg + wget -O $(DESTDIR)/assets/static/img/preview.jpg https://cdn.photoprism.app/img/preview.jpg cp scripts/dist/heif-convert.sh $(DESTDIR)/bin/heif-convert cp internal/config/testdata/*.yml $(DESTDIR)/config/examples chown -R $(INSTALL_USER) $(DESTDIR) diff --git a/assets/static/img/preview.jpg b/assets/static/img/preview.jpg index 2bd1f2550..d1534f2aa 100644 Binary files a/assets/static/img/preview.jpg and b/assets/static/img/preview.jpg differ diff --git a/docker-compose.ci.yml b/docker-compose.ci.yml index 09019f199..a59467659 100644 --- a/docker-compose.ci.yml +++ b/docker-compose.ci.yml @@ -22,7 +22,7 @@ services: PHOTOPRISM_SITE_AUTHOR: "@photoprism_app" PHOTOPRISM_DEBUG: "false" PHOTOPRISM_READONLY: "false" - PHOTOPRISM_PUBLIC: "true" + PHOTOPRISM_AUTH_MODE: "public" # authentication mode (public, password) PHOTOPRISM_PID_FILENAME: "photoprism.pid" PHOTOPRISM_LOG_FILENAME: "photoprism.log" PHOTOPRISM_DETACH_SERVER: "true" diff --git a/docker-compose.latest.yml b/docker-compose.latest.yml index 4969e1be6..e96f10abd 100644 --- a/docker-compose.latest.yml +++ b/docker-compose.latest.yml @@ -21,6 +21,7 @@ services: environment: PHOTOPRISM_UID: ${UID:-1000} # user id, should match your host user id PHOTOPRISM_GID: ${GID:-1000} # group id + PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password) PHOTOPRISM_ADMIN_PASSWORD: "photoprism" # initial "admin" password (minimum 8 characters) ## Public server URL incl http:// or https:// and /path, :port is optional PHOTOPRISM_SITE_URL: "https://latest.localssl.dev/" @@ -29,7 +30,6 @@ services: PHOTOPRISM_SITE_AUTHOR: "@photoprism_app" PHOTOPRISM_DEBUG: "true" PHOTOPRISM_READONLY: "false" - PHOTOPRISM_PUBLIC: "true" PHOTOPRISM_EXPERIMENTAL: "false" PHOTOPRISM_SERVER_MODE: "debug" PHOTOPRISM_HTTP_HOST: "0.0.0.0" diff --git a/docker-compose.local.yml b/docker-compose.local.yml index 0ea49d34d..5144ff8fd 100644 --- a/docker-compose.local.yml +++ b/docker-compose.local.yml @@ -21,6 +21,7 @@ services: environment: PHOTOPRISM_UID: ${UID:-1000} # user id, should match your host user id PHOTOPRISM_GID: ${GID:-1000} # group id + PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password) PHOTOPRISM_ADMIN_PASSWORD: "photoprism" # initial "admin" password (minimum 8 characters) ## Public server URL incl http:// or https:// and /path, :port is optional PHOTOPRISM_SITE_URL: "https://latest.localssl.dev/" @@ -29,7 +30,6 @@ services: PHOTOPRISM_SITE_AUTHOR: "@photoprism_app" PHOTOPRISM_DEBUG: "true" PHOTOPRISM_READONLY: "false" - PHOTOPRISM_PUBLIC: "true" PHOTOPRISM_EXPERIMENTAL: "false" PHOTOPRISM_SERVER_MODE: "debug" PHOTOPRISM_HTTP_HOST: "0.0.0.0" diff --git a/docker-compose.postgres.yml b/docker-compose.postgres.yml index 8c2e4ac28..2a76d9744 100644 --- a/docker-compose.postgres.yml +++ b/docker-compose.postgres.yml @@ -25,13 +25,14 @@ services: - "go-mod:/go/pkg/mod" shm_size: "2gb" environment: + PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password) + PHOTOPRISM_ADMIN_PASSWORD: "photoprism" # initial "admin" password (minimum 8 characters) PHOTOPRISM_SITE_URL: "http://localhost:2342/" PHOTOPRISM_SITE_CAPTION: "AI-Powered Photos App" PHOTOPRISM_SITE_DESCRIPTION: "Open-Source Photo Management" PHOTOPRISM_SITE_AUTHOR: "@photoprism_app" PHOTOPRISM_DEBUG: "true" PHOTOPRISM_READONLY: "false" - PHOTOPRISM_PUBLIC: "true" PHOTOPRISM_EXPERIMENTAL: "true" PHOTOPRISM_SERVER_MODE: "debug" PHOTOPRISM_HTTP_HOST: "0.0.0.0" @@ -43,7 +44,6 @@ services: PHOTOPRISM_DATABASE_USER: "photoprism" PHOTOPRISM_DATABASE_PASSWORD: "photoprism" PHOTOPRISM_TEST_DRIVER: "sqlite" - PHOTOPRISM_ADMIN_PASSWORD: "photoprism" # initial "admin" password (minimum 8 characters) PHOTOPRISM_ASSETS_PATH: "/go/src/github.com/photoprism/photoprism/assets" PHOTOPRISM_STORAGE_PATH: "/go/src/github.com/photoprism/photoprism/storage" PHOTOPRISM_ORIGINALS_PATH: "/go/src/github.com/photoprism/photoprism/storage/originals" diff --git a/docker-compose.yml b/docker-compose.yml index 8a815572f..d2f4b61d5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,6 +34,7 @@ services: ## Switch to a non-root user after initialization (supported IDs are 33, 50-99, 500-600, and 900-1200): PHOTOPRISM_UID: ${UID:-1000} # user id, should match your host user id PHOTOPRISM_GID: ${GID:-1000} # group id + PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password) PHOTOPRISM_ADMIN_PASSWORD: "photoprism" # initial "admin" password (minimum 8 characters) ## External development server URL incl http:// or https:// and /path, :port is optional PHOTOPRISM_SITE_URL: "https://app.localssl.dev/" @@ -42,7 +43,6 @@ services: PHOTOPRISM_SITE_AUTHOR: "@photoprism_app" PHOTOPRISM_DEBUG: "true" PHOTOPRISM_READONLY: "false" - PHOTOPRISM_PUBLIC: "true" PHOTOPRISM_EXPERIMENTAL: "true" PHOTOPRISM_SERVER_MODE: "debug" PHOTOPRISM_HTTP_HOST: "0.0.0.0" diff --git a/docker/examples/arm64/docker-compose.yml b/docker/examples/arm64/docker-compose.yml index 5ccf80a10..f4c8e0646 100644 --- a/docker/examples/arm64/docker-compose.yml +++ b/docker/examples/arm64/docker-compose.yml @@ -60,13 +60,13 @@ services: ports: - "2342:2342" # HTTP port (host:container) environment: + PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password) PHOTOPRISM_ADMIN_PASSWORD: "insecure" # YOUR INITIAL ADMIN PASSWORD (MINIMUM 8 CHARACTERS, USERNAME "admin") PHOTOPRISM_SITE_URL: "http://localhost:2342/" # public server URL incl http:// or https:// and /path, :port is optional PHOTOPRISM_ORIGINALS_LIMIT: 5000 # file size limit for originals in MB (increase for high-res video) PHOTOPRISM_HTTP_COMPRESSION: "none" # improves transfer speed and bandwidth utilization (none or gzip) PHOTOPRISM_WORKERS: 2 # limits the number of indexing workers to reduce system load PHOTOPRISM_LOG_LEVEL: "info" # log level: trace, debug, info, warning, error, fatal, or panic - PHOTOPRISM_PUBLIC: "false" # no authentication required (disables password protection) PHOTOPRISM_READONLY: "false" # do not modify originals directory (reduced functionality) PHOTOPRISM_EXPERIMENTAL: "false" # enables experimental features PHOTOPRISM_DISABLE_CHOWN: "false" # disables storage permission updates on startup diff --git a/docker/examples/armv7/docker-compose.yml b/docker/examples/armv7/docker-compose.yml index 581d41828..832fbb06c 100644 --- a/docker/examples/armv7/docker-compose.yml +++ b/docker/examples/armv7/docker-compose.yml @@ -55,13 +55,13 @@ services: ports: - "2342:2342" # HTTP port (host:container) environment: + PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password) PHOTOPRISM_ADMIN_PASSWORD: "insecure" # YOUR INITIAL ADMIN PASSWORD (MINIMUM 8 CHARACTERS, USERNAME "admin") PHOTOPRISM_SITE_URL: "http://localhost:2342/" # public server URL incl http:// or https:// and /path, :port is optional PHOTOPRISM_ORIGINALS_LIMIT: 5000 # file size limit for originals in MB (increase for high-res video) PHOTOPRISM_HTTP_COMPRESSION: "none" # improves transfer speed and bandwidth utilization (none or gzip) PHOTOPRISM_WORKERS: 1 # Limits the number of indexing workers to reduce system load PHOTOPRISM_LOG_LEVEL: "info" # log level: trace, debug, info, warning, error, fatal, or panic - PHOTOPRISM_PUBLIC: "false" # no authentication required (disables password protection) PHOTOPRISM_READONLY: "false" # do not modify originals directory (reduced functionality) PHOTOPRISM_EXPERIMENTAL: "false" # enables experimental features PHOTOPRISM_DISABLE_CHOWN: "false" # disables storage permission updates on startup diff --git a/docker/examples/cloud/docker-compose.yml b/docker/examples/cloud/docker-compose.yml index 17acf897b..7a8f75685 100644 --- a/docker/examples/cloud/docker-compose.yml +++ b/docker/examples/cloud/docker-compose.yml @@ -130,13 +130,13 @@ services: ## !! CHANGE site url if your server has a public domain name e.g. "https://photos.yourdomain.com/" !! PHOTOPRISM_SITE_URL: "https://_public_ip_/" PHOTOPRISM_SITE_CAPTION: "AI-Powered Photos App" - PHOTOPRISM_SITE_DESCRIPTION: "" # meta site description - PHOTOPRISM_SITE_AUTHOR: "" # meta site author + PHOTOPRISM_SITE_DESCRIPTION: "" # meta site description + PHOTOPRISM_SITE_AUTHOR: "" # meta site author + PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password) PHOTOPRISM_ADMIN_PASSWORD: "_admin_password_" # YOUR INITIAL "admin" PASSWORD PHOTOPRISM_ORIGINALS_LIMIT: 5000 # file size limit for originals in MB (increase for high-res video) PHOTOPRISM_HTTP_COMPRESSION: "gzip" # improves transfer speed and bandwidth utilization (none or gzip) PHOTOPRISM_LOG_LEVEL: "info" # log level: trace, debug, info, warning, error, fatal, or panic - PHOTOPRISM_PUBLIC: "false" # no authentication required (disables password protection) PHOTOPRISM_READONLY: "false" # do not modify originals directory (reduced functionality) PHOTOPRISM_EXPERIMENTAL: "false" # enables experimental features PHOTOPRISM_DISABLE_CHOWN: "false" # disables storage permission updates on startup diff --git a/docker/examples/docker-compose.yml b/docker/examples/docker-compose.yml index a1fd27602..4a0ef7b38 100644 --- a/docker/examples/docker-compose.yml +++ b/docker/examples/docker-compose.yml @@ -52,12 +52,12 @@ services: ports: - "2342:2342" # HTTP port (host:container) environment: + PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password) PHOTOPRISM_ADMIN_PASSWORD: "insecure" # YOUR INITIAL ADMIN PASSWORD (MINIMUM 8 CHARACTERS, USERNAME "admin") PHOTOPRISM_SITE_URL: "http://localhost:2342/" # public server URL incl http:// or https:// and /path, :port is optional PHOTOPRISM_ORIGINALS_LIMIT: 5000 # file size limit for originals in MB (increase for high-res video) PHOTOPRISM_HTTP_COMPRESSION: "gzip" # improves transfer speed and bandwidth utilization (none or gzip) PHOTOPRISM_LOG_LEVEL: "info" # log level: trace, debug, info, warning, error, fatal, or panic - PHOTOPRISM_PUBLIC: "false" # no authentication required (disables password protection) PHOTOPRISM_READONLY: "false" # do not modify originals directory (reduced functionality) PHOTOPRISM_EXPERIMENTAL: "false" # enables experimental features PHOTOPRISM_DISABLE_CHOWN: "false" # disables storage permission updates on startup diff --git a/docker/examples/macos/docker-compose.yml b/docker/examples/macos/docker-compose.yml index 6c739ba4c..322fc1c9d 100644 --- a/docker/examples/macos/docker-compose.yml +++ b/docker/examples/macos/docker-compose.yml @@ -49,12 +49,12 @@ services: ports: - "2342:2342" # HTTP port (host:container) environment: + PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password) PHOTOPRISM_ADMIN_PASSWORD: "insecure" # YOUR INITIAL ADMIN PASSWORD (MINIMUM 8 CHARACTERS, USERNAME "admin") PHOTOPRISM_SITE_URL: "http://localhost:2342/" # public server URL incl http:// or https:// and /path, :port is optional PHOTOPRISM_ORIGINALS_LIMIT: 5000 # file size limit for originals in MB (increase for high-res video) PHOTOPRISM_HTTP_COMPRESSION: "gzip" # improves transfer speed and bandwidth utilization (none or gzip) PHOTOPRISM_LOG_LEVEL: "info" # log level: trace, debug, info, warning, error, fatal, or panic - PHOTOPRISM_PUBLIC: "false" # no authentication required (disables password protection) PHOTOPRISM_READONLY: "false" # do not modify originals directory (reduced functionality) PHOTOPRISM_EXPERIMENTAL: "false" # enables experimental features PHOTOPRISM_DISABLE_CHOWN: "false" # disables storage permission updates on startup diff --git a/docker/examples/scheduler/docker-compose.yml b/docker/examples/scheduler/docker-compose.yml index 37280acdd..ca5ed3e6d 100644 --- a/docker/examples/scheduler/docker-compose.yml +++ b/docker/examples/scheduler/docker-compose.yml @@ -54,12 +54,12 @@ services: ports: - "2342:2342" # HTTP port (host:container) environment: + PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password) PHOTOPRISM_ADMIN_PASSWORD: "insecure" # YOUR INITIAL ADMIN PASSWORD (MINIMUM 8 CHARACTERS, USERNAME "admin") PHOTOPRISM_SITE_URL: "http://localhost:2342/" # public server URL incl http:// or https:// and /path, :port is optional PHOTOPRISM_ORIGINALS_LIMIT: 5000 # file size limit for originals in MB (increase for high-res video) PHOTOPRISM_HTTP_COMPRESSION: "gzip" # improves transfer speed and bandwidth utilization (none or gzip) PHOTOPRISM_LOG_LEVEL: "info" # log level: trace, debug, info, warning, error, fatal, or panic - PHOTOPRISM_PUBLIC: "false" # no authentication required (disables password protection) PHOTOPRISM_READONLY: "false" # do not modify originals directory (reduced functionality) PHOTOPRISM_EXPERIMENTAL: "false" # enables experimental features PHOTOPRISM_DISABLE_CHOWN: "false" # disables storage permission updates on startup diff --git a/docker/examples/sqlite/docker-compose.yml b/docker/examples/sqlite/docker-compose.yml index c2b8f7c6c..1084aa4ec 100644 --- a/docker/examples/sqlite/docker-compose.yml +++ b/docker/examples/sqlite/docker-compose.yml @@ -52,12 +52,12 @@ services: ports: - "2342:2342" # HTTP port (host:container) environment: + PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password) PHOTOPRISM_ADMIN_PASSWORD: "insecure" # YOUR INITIAL ADMIN PASSWORD (MINIMUM 8 CHARACTERS, USERNAME "admin") PHOTOPRISM_SITE_URL: "http://localhost:2342/" # public server URL incl http:// or https:// and /path, :port is optional PHOTOPRISM_ORIGINALS_LIMIT: 5000 # file size limit for originals in MB (increase for high-res video) PHOTOPRISM_HTTP_COMPRESSION: "gzip" # improves transfer speed and bandwidth utilization (none or gzip) PHOTOPRISM_LOG_LEVEL: "info" # log level: trace, debug, info, warning, error, fatal, or panic - PHOTOPRISM_PUBLIC: "false" # no authentication required (disables password protection) PHOTOPRISM_READONLY: "false" # do not modify originals directory (reduced functionality) PHOTOPRISM_EXPERIMENTAL: "false" # enables experimental features PHOTOPRISM_DISABLE_CHOWN: "false" # disables storage permission updates on startup diff --git a/docker/examples/windows/docker-compose.yml b/docker/examples/windows/docker-compose.yml index 6d833eb1b..903f9e1f9 100644 --- a/docker/examples/windows/docker-compose.yml +++ b/docker/examples/windows/docker-compose.yml @@ -54,12 +54,12 @@ services: ports: - "2342:2342" # HTTP port (host:container) environment: + PHOTOPRISM_AUTH_MODE: "password" # authentication mode (public, password) PHOTOPRISM_ADMIN_PASSWORD: "insecure" # YOUR INITIAL ADMIN PASSWORD (MINIMUM 8 CHARACTERS, USERNAME "admin") PHOTOPRISM_SITE_URL: "http://localhost:2342/" # public server URL incl http:// or https:// and /path, :port is optional PHOTOPRISM_ORIGINALS_LIMIT: 5000 # file size limit for originals in MB (increase for high-res video) PHOTOPRISM_HTTP_COMPRESSION: "gzip" # improves transfer speed and bandwidth utilization (none or gzip) PHOTOPRISM_DEBUG: "false" # run in debug mode, shows additional log messages - PHOTOPRISM_PUBLIC: "false" # no authentication required, disables password protection PHOTOPRISM_READONLY: "false" # do not modify originals folder; disables import, upload, and delete PHOTOPRISM_EXPERIMENTAL: "false" # enables experimental features PHOTOPRISM_DISABLE_CHOWN: "false" # disables storage permission updates on startup diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ec6430bd4..f5b48130e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -2027,9 +2027,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.8.tgz", - "integrity": "sha512-YK5G9LaddzGbcucK4c8h5tWFmMPBvRZ/uyWmN1/SbBdIvqGUdWGkJ5BAaccgs6XbzVLsqbPJrBSFwKv3kT9i7w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "engines": { "node": ">=6.0.0" } @@ -2242,9 +2242,9 @@ } }, "node_modules/@types/node": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.1.tgz", - "integrity": "sha512-CmR8+Tsy95hhwtZBKJBs0/FFq4XX7sDZHlGGf+0q+BRZfMbOTkzkj0AFAuTyXbObDIoanaBBW0+KEW+m3N16Wg==" + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.3.tgz", + "integrity": "sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ==" }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -4542,9 +4542,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.179", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.179.tgz", - "integrity": "sha512-1XeTb/U/8Xgh2YgPOqhakLYsvCcU4U7jUjTMbEnhIJoIWd/Qt3yC8y0cbG+fHzn4zUNF99Ey1xiPf20bwgLO3Q==" + "version": "1.4.182", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.182.tgz", + "integrity": "sha512-OpEjTADzGoXABjqobGhpy0D2YsTncAax7IkER68ycc4adaq0dqEG9//9aenKPy7BGA90bqQdLac0dPp6uMkcSg==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -5389,9 +5389,9 @@ } }, "node_modules/eslint-plugin-vue": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.1.1.tgz", - "integrity": "sha512-W9n5PB1X2jzC7CK6riG0oAcxjmKrjTF6+keL1rni8n57DZeilx/Fulz+IRJK3lYseLNAygN0I62L7DvioW40Tw==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.2.0.tgz", + "integrity": "sha512-W2hc+NUXoce8sZtWgZ45miQTy6jNyuSdub5aZ1IBune4JDeAyzucYX0TzkrQ1jMO52sNUDYlCIHDoaNePe0p5g==", "dependencies": { "eslint-utils": "^3.0.0", "natural-compare": "^1.4.0", @@ -6257,19 +6257,19 @@ "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==" }, "node_modules/flow-parser": { - "version": "0.181.2", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.181.2.tgz", - "integrity": "sha512-+QzNZEmhYNF9SHrKI8M2lzT07UGkJW6Zoeg7wP+aGkFxh0Mh/wx8eyS/lcwY9bd3B4azS6K50ZjyIjzMWpowGg==", + "version": "0.182.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.182.0.tgz", + "integrity": "sha512-Caoy6YFlh0jz+qWpMGuI2CEIDcQGa/YRRnQ5d8+jtj30weXApWDyTSN5gPNve9cQN73JKXE2LFnpZ5AOUI1bXA==", "engines": { "node": ">=0.4.0" } }, "node_modules/flow-remove-types": { - "version": "2.181.2", - "resolved": "https://registry.npmjs.org/flow-remove-types/-/flow-remove-types-2.181.2.tgz", - "integrity": "sha512-Szb/cGyXeKQWL470qucaW2Xp7028TAshVORIULnpreMcRPiSFKm1DQpjn3LXUrg9uNUYq2z+i1+VABBU1rMc2w==", + "version": "2.182.0", + "resolved": "https://registry.npmjs.org/flow-remove-types/-/flow-remove-types-2.182.0.tgz", + "integrity": "sha512-pgNt8By+h7tEF+zQnxHQBcDpFZjR6hgu+XgBfBw+qqGZwBOH3UMde807nmfYFCRmXUQYe4UKKRjK7fDXfoNCNA==", "dependencies": { - "flow-parser": "^0.181.2", + "flow-parser": "^0.182.0", "pirates": "^3.0.2", "vlq": "^0.2.1" }, @@ -8020,11 +8020,11 @@ } }, "node_modules/log4js": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.5.2.tgz", - "integrity": "sha512-DXtpNtt+KDOMT7RHUDIur/WsSA3rntlUh9Zg4XCdV42wUuMmbFkl38+LZ92Z5QvQA7mD5kAVkLiBSEH/tvUB8A==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.6.0.tgz", + "integrity": "sha512-3v8R7fd45UB6THucSht6wN2/7AZEruQbXdjygPZcxt5TA/msO6si9CN5MefUuKXbYnJHTBnYcx4famwcyQd+sA==", "dependencies": { - "date-format": "^4.0.10", + "date-format": "^4.0.11", "debug": "^4.3.4", "flatted": "^3.2.5", "rfdc": "^1.3.0", @@ -12204,11 +12204,11 @@ } }, "node_modules/vue": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.2.tgz", - "integrity": "sha512-fQPKEfdiUP4bDlrGEjI5MOTkC5s/XIbnfKAx0B3MxJHI4qwh8FPLSo8/9tFkgFiRH3HwvcHjZQ1tCTifOUH0tg==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.3.tgz", + "integrity": "sha512-7MTirXG7LYJi3r2jeYy7EiXIhEE85uP3kBwSxqwDsvIfy/l7+qR4U6ajw8ji1KoP+wYYg7ZY28TBTf3P3Fa4Nw==", "dependencies": { - "@vue/compiler-sfc": "2.7.2", + "@vue/compiler-sfc": "2.7.3", "csstype": "^3.1.0" } }, @@ -12458,9 +12458,9 @@ } }, "node_modules/vue-template-compiler": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.2.tgz", - "integrity": "sha512-3PDLIPankm7b1YZHk6/mTz9kMZaDSd1Vhp1tFPITot5uW9WjnIyv6zRax3+j1kwF0DHmvfIVXMX8G+Rn/BHfaQ==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.3.tgz", + "integrity": "sha512-QKcV4vj9akZ2zSD1+F7tci3aXpRe5DXU3TZ/ZWJPE9gInXD5UoV+Q2PrCaplj4IGIK8JXRHYaSvOXkOn7tg9Og==", "dependencies": { "de-indent": "^1.0.2", "he": "^1.2.0" @@ -12472,9 +12472,9 @@ "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==" }, "node_modules/vue/node_modules/@vue/compiler-sfc": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.2.tgz", - "integrity": "sha512-khG5m63A4DSeHEOe5yyjHQY2TAE0pUXqKqxgauNUcFaa8M4+J55OWhagy8Bk8O6cO4GhKbQf2NDYzceijmOy8A==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.3.tgz", + "integrity": "sha512-/9SO6KeR1ljo+j4Tdkl9zsFG2yY4NQ9p3GKdPVCU99bmkNkTW8g9Tq8SMEvhOfo+RhBC0PdDAOmibl+N37f5YA==", "dependencies": { "@babel/parser": "^7.18.4", "postcss": "^8.4.14", @@ -14386,9 +14386,9 @@ } }, "@jridgewell/resolve-uri": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.8.tgz", - "integrity": "sha512-YK5G9LaddzGbcucK4c8h5tWFmMPBvRZ/uyWmN1/SbBdIvqGUdWGkJ5BAaccgs6XbzVLsqbPJrBSFwKv3kT9i7w==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" }, "@jridgewell/set-array": { "version": "1.1.2", @@ -14581,9 +14581,9 @@ } }, "@types/node": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.1.tgz", - "integrity": "sha512-CmR8+Tsy95hhwtZBKJBs0/FFq4XX7sDZHlGGf+0q+BRZfMbOTkzkj0AFAuTyXbObDIoanaBBW0+KEW+m3N16Wg==" + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.3.tgz", + "integrity": "sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ==" }, "@types/parse-json": { "version": "4.0.0", @@ -16299,9 +16299,9 @@ } }, "electron-to-chromium": { - "version": "1.4.179", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.179.tgz", - "integrity": "sha512-1XeTb/U/8Xgh2YgPOqhakLYsvCcU4U7jUjTMbEnhIJoIWd/Qt3yC8y0cbG+fHzn4zUNF99Ey1xiPf20bwgLO3Q==" + "version": "1.4.182", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.182.tgz", + "integrity": "sha512-OpEjTADzGoXABjqobGhpy0D2YsTncAax7IkER68ycc4adaq0dqEG9//9aenKPy7BGA90bqQdLac0dPp6uMkcSg==" }, "emoji-regex": { "version": "8.0.0", @@ -17021,9 +17021,9 @@ "requires": {} }, "eslint-plugin-vue": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.1.1.tgz", - "integrity": "sha512-W9n5PB1X2jzC7CK6riG0oAcxjmKrjTF6+keL1rni8n57DZeilx/Fulz+IRJK3lYseLNAygN0I62L7DvioW40Tw==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.2.0.tgz", + "integrity": "sha512-W2hc+NUXoce8sZtWgZ45miQTy6jNyuSdub5aZ1IBune4JDeAyzucYX0TzkrQ1jMO52sNUDYlCIHDoaNePe0p5g==", "requires": { "eslint-utils": "^3.0.0", "natural-compare": "^1.4.0", @@ -17554,16 +17554,16 @@ "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==" }, "flow-parser": { - "version": "0.181.2", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.181.2.tgz", - "integrity": "sha512-+QzNZEmhYNF9SHrKI8M2lzT07UGkJW6Zoeg7wP+aGkFxh0Mh/wx8eyS/lcwY9bd3B4azS6K50ZjyIjzMWpowGg==" + "version": "0.182.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.182.0.tgz", + "integrity": "sha512-Caoy6YFlh0jz+qWpMGuI2CEIDcQGa/YRRnQ5d8+jtj30weXApWDyTSN5gPNve9cQN73JKXE2LFnpZ5AOUI1bXA==" }, "flow-remove-types": { - "version": "2.181.2", - "resolved": "https://registry.npmjs.org/flow-remove-types/-/flow-remove-types-2.181.2.tgz", - "integrity": "sha512-Szb/cGyXeKQWL470qucaW2Xp7028TAshVORIULnpreMcRPiSFKm1DQpjn3LXUrg9uNUYq2z+i1+VABBU1rMc2w==", + "version": "2.182.0", + "resolved": "https://registry.npmjs.org/flow-remove-types/-/flow-remove-types-2.182.0.tgz", + "integrity": "sha512-pgNt8By+h7tEF+zQnxHQBcDpFZjR6hgu+XgBfBw+qqGZwBOH3UMde807nmfYFCRmXUQYe4UKKRjK7fDXfoNCNA==", "requires": { - "flow-parser": "^0.181.2", + "flow-parser": "^0.182.0", "pirates": "^3.0.2", "vlq": "^0.2.1" }, @@ -18798,11 +18798,11 @@ } }, "log4js": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.5.2.tgz", - "integrity": "sha512-DXtpNtt+KDOMT7RHUDIur/WsSA3rntlUh9Zg4XCdV42wUuMmbFkl38+LZ92Z5QvQA7mD5kAVkLiBSEH/tvUB8A==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.6.0.tgz", + "integrity": "sha512-3v8R7fd45UB6THucSht6wN2/7AZEruQbXdjygPZcxt5TA/msO6si9CN5MefUuKXbYnJHTBnYcx4famwcyQd+sA==", "requires": { - "date-format": "^4.0.10", + "date-format": "^4.0.11", "debug": "^4.3.4", "flatted": "^3.2.5", "rfdc": "^1.3.0", @@ -21742,18 +21742,18 @@ } }, "vue": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.2.tgz", - "integrity": "sha512-fQPKEfdiUP4bDlrGEjI5MOTkC5s/XIbnfKAx0B3MxJHI4qwh8FPLSo8/9tFkgFiRH3HwvcHjZQ1tCTifOUH0tg==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.3.tgz", + "integrity": "sha512-7MTirXG7LYJi3r2jeYy7EiXIhEE85uP3kBwSxqwDsvIfy/l7+qR4U6ajw8ji1KoP+wYYg7ZY28TBTf3P3Fa4Nw==", "requires": { - "@vue/compiler-sfc": "2.7.2", + "@vue/compiler-sfc": "2.7.3", "csstype": "^3.1.0" }, "dependencies": { "@vue/compiler-sfc": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.2.tgz", - "integrity": "sha512-khG5m63A4DSeHEOe5yyjHQY2TAE0pUXqKqxgauNUcFaa8M4+J55OWhagy8Bk8O6cO4GhKbQf2NDYzceijmOy8A==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.3.tgz", + "integrity": "sha512-/9SO6KeR1ljo+j4Tdkl9zsFG2yY4NQ9p3GKdPVCU99bmkNkTW8g9Tq8SMEvhOfo+RhBC0PdDAOmibl+N37f5YA==", "requires": { "@babel/parser": "^7.18.4", "postcss": "^8.4.14", @@ -21943,9 +21943,9 @@ } }, "vue-template-compiler": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.2.tgz", - "integrity": "sha512-3PDLIPankm7b1YZHk6/mTz9kMZaDSd1Vhp1tFPITot5uW9WjnIyv6zRax3+j1kwF0DHmvfIVXMX8G+Rn/BHfaQ==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.3.tgz", + "integrity": "sha512-QKcV4vj9akZ2zSD1+F7tci3aXpRe5DXU3TZ/ZWJPE9gInXD5UoV+Q2PrCaplj4IGIK8JXRHYaSvOXkOn7tg9Og==", "requires": { "de-indent": "^1.0.2", "he": "^1.2.0" diff --git a/frontend/src/pages/about/about.vue b/frontend/src/pages/about/about.vue index 63e57e398..4daad78ef 100644 --- a/frontend/src/pages/about/about.vue +++ b/frontend/src/pages/about/about.vue @@ -12,13 +12,13 @@ -

+

PhotoPrism® is an AI-Powered Photos App for the Decentralized Web. It makes use of the latest technologies to tag and find pictures automatically without getting in your way. You can run it at home, on a private server, or in the cloud.

-

+

Your continued support helps us provide regular updates and remain independent, so we can fulfill our mission and protect your privacy. @@ -50,7 +50,7 @@

User Guide

-

+

Visit docs.photoprism.app/user-guide to learn how to sync, organize, and share your pictures. Our User Guide also covers many advanced topics, such as migrating from Google Photos and thumbnail quality settings. Common issues can be quickly diagnosed and solved using the troubleshooting checklists we provide. @@ -58,13 +58,13 @@

Read the docs ›

Knowledge Base

-

Browse the Knowledge Base for detailed information on specific product features, services, and related resources.

+

Browse the Knowledge Base for detailed information on specific product features, services, and related resources.

Learn more ›

Getting Support

-

+

Before submitting a support request, please use our Troubleshooting Checklists to determine the cause of your problem. If this doesn't help, or you have other questions: @@ -75,7 +75,7 @@

  • post your question in GitHub Discussions
  • or ask in our Community Chat
  • -

    +

    In addition, sponsors receive direct technical support via email. We'll do our best to answer all your questions. In return, we ask you to back us on Patreon or GitHub Sponsors. diff --git a/go.mod b/go.mod index 4ac0417f0..9019d1255 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/urfave/cli v1.22.9 go4.org v0.0.0-20201209231011-d4a079459e60 // indirect golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d - golang.org/x/net v0.0.0-20220630215102-69896b714898 + golang.org/x/net v0.0.0-20220706163947-c90051bbdb60 gonum.org/v1/gonum v0.11.0 gopkg.in/photoprism/go-tz.v2 v2.1.1 gopkg.in/yaml.v2 v2.4.0 diff --git a/go.sum b/go.sum index 28263267d..8fab8308e 100644 --- a/go.sum +++ b/go.sum @@ -408,8 +408,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220630215102-69896b714898 h1:K7wO6V1IrczY9QOQ2WkVpw4JQSwCd52UsxVEirZUfiw= -golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220706163947-c90051bbdb60 h1:8NSylCMxLW4JvserAndSgFL7aPli6A68yf0bYFTcWCM= +golang.org/x/net v0.0.0-20220706163947-c90051bbdb60/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= diff --git a/internal/config/config.go b/internal/config/config.go index cbf70cab6..add66f844 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -481,24 +481,6 @@ func (c *Config) NoSponsor() bool { return !c.Sponsor() && !c.Demo() } -// Public checks if app runs in public mode and requires no authentication. -func (c *Config) Public() bool { - if c.Auth() { - return false - } else if c.Demo() { - return true - } - - return c.options.Public -} - -// SetPublic changes authentication while instance is running, for testing purposes only. -func (c *Config) SetPublic(p bool) { - if c.Debug() { - c.options.Public = p - } -} - // Experimental checks if experimental features should be enabled. func (c *Config) Experimental() bool { return c.options.Experimental @@ -519,21 +501,6 @@ func (c *Config) UploadNSFW() bool { return c.options.UploadNSFW } -// AdminPassword returns the initial admin password. -func (c *Config) AdminPassword() string { - return c.options.AdminPassword -} - -// AuthMode returns the authentication mode. -func (c *Config) AuthMode() string { - return strings.ToLower(strings.TrimSpace(c.options.AuthMode)) -} - -// Auth checks if authentication is required. -func (c *Config) Auth() bool { - return c.AuthMode() != "" -} - // LogLevel returns the Logrus log level. func (c *Config) LogLevel() logrus.Level { // Normalize string. diff --git a/internal/config/config_auth.go b/internal/config/config_auth.go index 70ef55166..f36423552 100644 --- a/internal/config/config_auth.go +++ b/internal/config/config_auth.go @@ -2,11 +2,17 @@ package config import ( "regexp" + "strings" "github.com/photoprism/photoprism/pkg/rnd" "golang.org/x/crypto/bcrypt" ) +const ( + AuthModePublic = "public" + AuthModePassword = "password" +) + func isBcrypt(s string) bool { b, err := regexp.MatchString(`^\$2[ayb]\$.{56}$`, s) if err != nil { @@ -15,6 +21,43 @@ func isBcrypt(s string) bool { return b } +// Public checks if app runs in public mode and requires no authentication. +func (c *Config) Public() bool { + if c.Demo() { + return true + } + + return c.options.Public +} + +// SetPublic changes authentication while instance is running, for testing purposes only. +func (c *Config) SetPublic(enabled bool) { + if c.Debug() { + c.options.Public = enabled + } +} + +// AdminPassword returns the initial admin password. +func (c *Config) AdminPassword() string { + return c.options.AdminPassword +} + +// AuthMode returns the authentication mode. +func (c *Config) AuthMode() string { + if c.Public() { + return AuthModePublic + } else if m := strings.ToLower(strings.TrimSpace(c.options.AuthMode)); m != "" { + return m + } + + return AuthModePassword +} + +// Auth checks if authentication is required. +func (c *Config) Auth() bool { + return c.AuthMode() != AuthModePublic +} + // CheckPassword compares given password p with the admin password func (c *Config) CheckPassword(p string) bool { ap := c.AdminPassword() diff --git a/internal/config/config_auth_test.go b/internal/config/config_auth_test.go index de6aaeda7..0a3d212ed 100644 --- a/internal/config/config_auth_test.go +++ b/internal/config/config_auth_test.go @@ -6,6 +6,30 @@ import ( "github.com/stretchr/testify/assert" ) +func TestAuthMode(t *testing.T) { + c := NewConfig(CliTestContext()) + c.options.Public = true + c.options.Demo = false + assert.Equal(t, AuthModePublic, c.AuthMode()) + c.options.Public = false + c.options.Demo = false + assert.Equal(t, AuthModePassword, c.AuthMode()) + c.options.Demo = true + assert.Equal(t, AuthModePublic, c.AuthMode()) +} + +func TestAuth(t *testing.T) { + c := NewConfig(CliTestContext()) + c.options.Public = true + c.options.Demo = false + assert.False(t, c.Auth()) + c.options.Public = false + c.options.Demo = false + assert.True(t, c.Auth()) + c.options.Demo = true + assert.False(t, c.Auth()) +} + func TestUtils_CheckPassword(t *testing.T) { c := NewConfig(CliTestContext()) diff --git a/internal/config/config_report.go b/internal/config/config_report.go index 52422a4aa..d618f30b4 100644 --- a/internal/config/config_report.go +++ b/internal/config/config_report.go @@ -13,8 +13,8 @@ func (c *Config) Report() (rows [][]string, cols []string) { rows = [][]string{ // Authentication. + {"auth-mode", fmt.Sprintf("%s", c.AuthMode())}, {"admin-password", strings.Repeat("*", utf8.RuneCountInString(c.AdminPassword()))}, - {"auth", fmt.Sprintf("%t", c.Auth())}, {"public", fmt.Sprintf("%t", c.Public())}, // Logging. diff --git a/internal/config/global_options.go b/internal/config/options.go similarity index 100% rename from internal/config/global_options.go rename to internal/config/options.go index 10d622910..8fa12bf15 100644 --- a/internal/config/global_options.go +++ b/internal/config/options.go @@ -24,12 +24,12 @@ type Options struct { Version string `json:"-"` Copyright string `json:"-"` PartnerID string `yaml:"-" json:"-" flag:"partner-id"` + AuthMode string `yaml:"AuthMode" json:"-" flag:"auth-mode"` + Public bool `yaml:"Public" json:"-" flag:"public"` AdminPassword string `yaml:"AdminPassword" json:"-" flag:"admin-password"` LogLevel string `yaml:"LogLevel" json:"-" flag:"log-level"` Debug bool `yaml:"Debug" json:"Debug" flag:"debug"` Trace bool `yaml:"Trace" json:"Trace" flag:"Trace"` - AuthMode string `yaml:"AuthMode" json:"-" flag:"auth-mode"` - Public bool `yaml:"Public" json:"-" flag:"public"` Test bool `yaml:"-" json:"Test,omitempty" flag:"test"` Unsafe bool `yaml:"-" json:"-" flag:"unsafe"` Demo bool `yaml:"Demo" json:"-" flag:"demo"` diff --git a/internal/config/global_flags.go b/internal/config/options_cli.go similarity index 98% rename from internal/config/global_flags.go rename to internal/config/options_cli.go index 3f423cb63..c49c7b0ee 100644 --- a/internal/config/global_flags.go +++ b/internal/config/options_cli.go @@ -12,8 +12,15 @@ import ( "github.com/photoprism/photoprism/internal/thumb" ) -// Flags lists all global command-line parameters. +// Flags configures the global command-line interface (CLI) parameters. var Flags = CliFlags{ + CliFlag{ + Flag: cli.StringFlag{ + Name: "auth-mode, a", + Usage: "authentication `MODE` (public, password)", + Value: "password", + EnvVar: "PHOTOPRISM_AUTH_MODE", + }}, CliFlag{ Flag: cli.StringFlag{ Name: "admin-password, pw", @@ -22,8 +29,9 @@ var Flags = CliFlags{ }}, CliFlag{ Flag: cli.BoolFlag{ - Name: "public", - Usage: "disable password authentication, incl WebDAV and Advanced Settings", + Name: "public, p", + Hidden: true, + Usage: "disable authentication, advanced settings, and WebDAV remote access", EnvVar: "PHOTOPRISM_PUBLIC", }}, CliFlag{ diff --git a/internal/config/global_options_test.go b/internal/config/options_test.go similarity index 100% rename from internal/config/global_options_test.go rename to internal/config/options_test.go