mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-07-30 13:11:39 +00:00
Compare commits
16 commits
321aac5151
...
3db982b60e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3db982b60e | ||
|
|
57a0dfdbdb | ||
|
|
61dcc99597 | ||
|
|
cf8826a906 | ||
|
|
4b00541dd6 | ||
|
|
93ab410857 | ||
|
|
cb28afcdf5 | ||
|
|
f888e10827 | ||
|
|
c229208bd5 | ||
|
|
6e5d1c967f | ||
|
|
c2ec0ee12b | ||
|
|
6ae4381551 | ||
|
|
e018e1d821 | ||
|
|
4b6a3ba72b | ||
|
|
c547500031 | ||
|
|
4b119490ca |
24 changed files with 1330 additions and 1114 deletions
|
|
@ -51,5 +51,9 @@
|
||||||
# Disable Topics tracking if not enabled explicitly: https://github.com/jkarlin/topics
|
# Disable Topics tracking if not enabled explicitly: https://github.com/jkarlin/topics
|
||||||
header ?Permissions-Policy "browsing-topics=()"
|
header ?Permissions-Policy "browsing-topics=()"
|
||||||
|
|
||||||
|
# Prevent PHP execution in the media upload directory
|
||||||
|
@php_in_media path_regexp (?i)^/media/.*\.(php[3-8]?|phar|phtml|pht|phps)$
|
||||||
|
respond @php_in_media 403
|
||||||
|
|
||||||
php_server
|
php_server
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,14 @@
|
||||||
AllowOverride All
|
AllowOverride All
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
|
# Prevent PHP execution in the media upload directory (server-level, not .htaccess,
|
||||||
|
# because public/media is a Docker volume and .htaccess there may not be present)
|
||||||
|
<Directory /var/www/html/public/media>
|
||||||
|
<FilesMatch "(?i)\.(php[3-8]?|phar|phtml|pht|phps)$">
|
||||||
|
Require all denied
|
||||||
|
</FilesMatch>
|
||||||
|
</Directory>
|
||||||
|
|
||||||
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
|
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
|
||||||
# error, crit, alert, emerg.
|
# error, crit, alert, emerg.
|
||||||
# It is also possible to configure the loglevel for particular
|
# It is also possible to configure the loglevel for particular
|
||||||
|
|
|
||||||
5
.env
5
.env
|
|
@ -1,6 +1,10 @@
|
||||||
#### Part-DB Configuration
|
#### Part-DB Configuration
|
||||||
# See https://docs.part-db.de/configuration.html for documentation of available options
|
# See https://docs.part-db.de/configuration.html for documentation of available options
|
||||||
|
|
||||||
|
# Change this to a random value to secure your installation! You can generate a random string with "openssl rand -hex 16"
|
||||||
|
# Share that value with nobody and keep it secret
|
||||||
|
APP_SECRET=a03498528f5a5fc089273ec9ae5b2849
|
||||||
|
|
||||||
###################################################################################
|
###################################################################################
|
||||||
# Database settings
|
# Database settings
|
||||||
###################################################################################
|
###################################################################################
|
||||||
|
|
@ -158,7 +162,6 @@ CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$'
|
||||||
|
|
||||||
###> symfony/framework-bundle ###
|
###> symfony/framework-bundle ###
|
||||||
APP_ENV=prod
|
APP_ENV=prod
|
||||||
APP_SECRET=a03498528f5a5fc089273ec9ae5b2849
|
|
||||||
APP_SHARE_DIR=var/share
|
APP_SHARE_DIR=var/share
|
||||||
###< symfony/framework-bundle ###
|
###< symfony/framework-bundle ###
|
||||||
|
|
||||||
|
|
|
||||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
2.12.0
|
2.12.1
|
||||||
|
|
|
||||||
819
composer.lock
generated
819
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -2436,6 +2436,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||||
* },
|
* },
|
||||||
* jsonapi?: array{
|
* jsonapi?: array{
|
||||||
* use_iri_as_id?: bool|Param, // Set to false to use entity identifiers instead of IRIs as the "id" field in JSON:API responses. // Default: true
|
* use_iri_as_id?: bool|Param, // Set to false to use entity identifiers instead of IRIs as the "id" field in JSON:API responses. // Default: true
|
||||||
|
* allow_client_generated_id?: bool|Param, // Allow client-generated IDs on JSON:API POST per https://jsonapi.org/format/#crud-creating-client-ids. Off by default to prevent id spoofing on public endpoints. // Default: false
|
||||||
* },
|
* },
|
||||||
* eager_loading?: bool|array{
|
* eager_loading?: bool|array{
|
||||||
* enabled?: bool|Param, // Default: true
|
* enabled?: bool|Param, // Default: true
|
||||||
|
|
|
||||||
|
|
@ -114,10 +114,21 @@ bundled with Part-DB. Set `DATABASE_MYSQL_SSL_VERIFY_CERT` if you want to accept
|
||||||
* `datastructure_create`: Creation of a new data structure (e.g. category, manufacturer, ...)
|
* `datastructure_create`: Creation of a new data structure (e.g. category, manufacturer, ...)
|
||||||
* `CHECK_FOR_UPDATES` (default `1`): Set this to 0 if you do not want Part-DB to connect to GitHub to check for new
|
* `CHECK_FOR_UPDATES` (default `1`): Set this to 0 if you do not want Part-DB to connect to GitHub to check for new
|
||||||
versions, or if your server cannot connect to the internet.
|
versions, or if your server cannot connect to the internet.
|
||||||
* `APP_SECRET` (env only): This variable is a configuration parameter used for various security-related purposes,
|
* `APP_SECRET` (env only): A secret key used by Symfony for cryptographic operations — signing cookies, generating
|
||||||
particularly for securing and protecting various aspects of your application. It's a secret key that is used for
|
CSRF tokens, and other security-sensitive tasks. **You must change this from the default value before exposing
|
||||||
cryptographic operations and security measures (session management, CSRF protection, etc..). Therefore this
|
Part-DB to any network.** The default value shipped with Part-DB is publicly known; leaving it in place would allow
|
||||||
value should be handled as confidential data and not shared publicly.
|
an attacker to forge signed cookies and bypass CSRF protection.
|
||||||
|
|
||||||
|
Generate a secure value and add it to `.env.local`:
|
||||||
|
```bash
|
||||||
|
echo "APP_SECRET=$(openssl rand -hex 32)" >> .env.local
|
||||||
|
```
|
||||||
|
For Docker, pass it in the `environment` section of your `docker-compose.yaml`:
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
- APP_SECRET=<output of: openssl rand -hex 32>
|
||||||
|
```
|
||||||
|
Part-DB displays a warning on the homepage (visible to administrators only) as long as the default value is in use.
|
||||||
* `SHOW_PART_IMAGE_OVERLAY`: Set to 0 to disable the part image overlay, which appears if you hover over an image in the
|
* `SHOW_PART_IMAGE_OVERLAY`: Set to 0 to disable the part image overlay, which appears if you hover over an image in the
|
||||||
part image gallery
|
part image gallery
|
||||||
* `IPN_SUGGEST_REGEX`: A global regular expression, that part IPNs have to fulfill. Enforce your own format for your users.
|
* `IPN_SUGGEST_REGEX`: A global regular expression, that part IPNs have to fulfill. Enforce your own format for your users.
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,9 @@ services:
|
||||||
- DATABASE_URL=sqlite:///%kernel.project_dir%/var/db/app.db
|
- DATABASE_URL=sqlite:///%kernel.project_dir%/var/db/app.db
|
||||||
# In docker env logs will be redirected to stderr
|
# In docker env logs will be redirected to stderr
|
||||||
- APP_ENV=docker
|
- APP_ENV=docker
|
||||||
|
# Secret key used to sign cookies and CSRF tokens. MUST be changed to a unique random value before going live!
|
||||||
|
# Generate one with: openssl rand -hex 32
|
||||||
|
- APP_SECRET=CHANGE_ME
|
||||||
|
|
||||||
# Uncomment this, if you want to use the automatic database migration feature. With this you have you do not have to
|
# Uncomment this, if you want to use the automatic database migration feature. With this you have you do not have to
|
||||||
# run the doctrine:migrations:migrate commands on installation or upgrade. A database backup is written to the uploads/
|
# run the doctrine:migrations:migrate commands on installation or upgrade. A database backup is written to the uploads/
|
||||||
|
|
@ -89,7 +92,11 @@ services:
|
||||||
|
|
||||||
4. Customize the settings by changing the environment variables (or adding new ones). See [Configuration]({% link
|
4. Customize the settings by changing the environment variables (or adding new ones). See [Configuration]({% link
|
||||||
configuration.md %}) for more information.
|
configuration.md %}) for more information.
|
||||||
5. Inside the folder, run
|
5. Make sure to change the `APP_SECRET` variable to a unique random value (32 characters). You can generate one with the following command:
|
||||||
|
```bash
|
||||||
|
openssl rand -hex 32
|
||||||
|
```
|
||||||
|
6. Inside the folder, run
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
|
|
@ -100,7 +107,7 @@ services:
|
||||||
> Otherwise Part-DB console might use the wrong configuration to execute commands.
|
> Otherwise Part-DB console might use the wrong configuration to execute commands.
|
||||||
|
|
||||||
|
|
||||||
6. Create the initial database with
|
7. Create the initial database with
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker exec --user=www-data partdb php bin/console doctrine:migrations:migrate
|
docker exec --user=www-data partdb php bin/console doctrine:migrations:migrate
|
||||||
|
|
@ -108,7 +115,7 @@ docker exec --user=www-data partdb php bin/console doctrine:migrations:migrate
|
||||||
|
|
||||||
and watch for the password output
|
and watch for the password output
|
||||||
|
|
||||||
6. Part-DB is available under `http://localhost:8080` and you can log in with the username `admin` and the password shown
|
8. Part-DB is available under `http://localhost:8080` and you can log in with the username `admin` and the password shown
|
||||||
before
|
before
|
||||||
|
|
||||||
The docker image uses a SQLite database and all data (database, uploads, and other media) is put into folders relative to
|
The docker image uses a SQLite database and all data (database, uploads, and other media) is put into folders relative to
|
||||||
|
|
@ -121,6 +128,7 @@ If you want to use MySQL as a database, you can use the following docker-compose
|
||||||
{: .warning }
|
{: .warning }
|
||||||
> You have to replace the values for MYSQL_ROOT_PASSWORD and MYSQL_PASSWORD with your own passwords!!
|
> You have to replace the values for MYSQL_ROOT_PASSWORD and MYSQL_PASSWORD with your own passwords!!
|
||||||
> You have to change MYSQL_PASSWORD in the database section and for the DATABASE_URL in the partdb section.
|
> You have to change MYSQL_PASSWORD in the database section and for the DATABASE_URL in the partdb section.
|
||||||
|
> Generate a random string for APP_SECRET.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: '3.3'
|
version: '3.3'
|
||||||
|
|
@ -142,14 +150,19 @@ services:
|
||||||
environment:
|
environment:
|
||||||
# Replace SECRET_USER_PASSWORD with the value of MYSQL_PASSWORD from below
|
# Replace SECRET_USER_PASSWORD with the value of MYSQL_PASSWORD from below
|
||||||
- DATABASE_URL=mysql://partdb:SECRET_USER_PASSWORD@database:3306/partdb
|
- DATABASE_URL=mysql://partdb:SECRET_USER_PASSWORD@database:3306/partdb
|
||||||
|
|
||||||
|
# Secret key used to sign cookies. MUST be changed to a unique random value before going live!
|
||||||
|
# Generate one with: openssl rand -hex 32
|
||||||
|
- APP_SECRET=CHANGE_ME
|
||||||
|
|
||||||
# In docker env logs will be redirected to stderr
|
# In docker env logs will be redirected to stderr
|
||||||
- APP_ENV=docker
|
- APP_ENV=docker
|
||||||
|
|
||||||
# Uncomment this, if you want to use the automatic database migration feature. With this you do not have to
|
# Uncomment this, if you want to use the automatic database migration feature. With this you do not have to
|
||||||
# run the doctrine:migrations:migrate commands on installation or upgrade. A database backup is written to the uploads/
|
# run the doctrine:migrations:migrate commands on installation or upgrade. A database backup is written to the uploads/
|
||||||
# folder (under .automigration-backup), so you can restore it, if the migration fails.
|
# folder (under .automigration-backup), so you can restore it, if the migration fails.
|
||||||
# This feature is currently experimental, so use it at your own risk!
|
# This feature is currently experimental, so use it at your own risk!
|
||||||
# - DB_AUTOMIGRATE=true
|
# - DB_AUTOMIGRATE=true
|
||||||
|
|
||||||
# You can configure Part-DB using the webUI or environment variables
|
# You can configure Part-DB using the webUI or environment variables
|
||||||
# However you can add any other environment configuration you want here
|
# However you can add any other environment configuration you want here
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,15 @@ cp .env .env.local
|
||||||
In your `.env.local` you can configure Part-DB according to your wishes and overwrite web interface settings.
|
In your `.env.local` you can configure Part-DB according to your wishes and overwrite web interface settings.
|
||||||
A full list of configuration options can be found [here](../configuration.md).
|
A full list of configuration options can be found [here](../configuration.md).
|
||||||
|
|
||||||
|
{: .important }
|
||||||
|
> **Change `APP_SECRET` before going live.** The default value shipped with Part-DB is publicly known and must not be
|
||||||
|
> used in production — it would allow an attacker to forge signed cookies and bypass CSRF protection.
|
||||||
|
> Generate a new value and add it to your `.env.local`:
|
||||||
|
> ```bash
|
||||||
|
> echo "APP_SECRET=$(openssl rand -hex 32)" >> .env.local
|
||||||
|
> ```
|
||||||
|
> or edit the file with a text editor and add a new value for `APP_SECRET` (you can generate a random value with `openssl rand -hex 32`).
|
||||||
|
|
||||||
Please check that the configured base currency matches your mainly used currency, as
|
Please check that the configured base currency matches your mainly used currency, as
|
||||||
this can not be changed after creating price information.
|
this can not be changed after creating price information.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,11 @@ server {
|
||||||
return 404;
|
return 404;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Prevent PHP execution in the media upload directory
|
||||||
|
location ~* ^/media/.*\.(php[3-8]?|phar|phtml|pht|phps)$ {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
|
||||||
# Set Content-Security-Policy for svg files, to block embedded javascript in there
|
# Set Content-Security-Policy for svg files, to block embedded javascript in there
|
||||||
location ~* \.svg$ {
|
location ~* \.svg$ {
|
||||||
add_header Content-Security-Policy "default-src 'self'; script-src 'none'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none';";
|
add_header Content-Security-Policy "default-src 'self'; script-src 'none'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none';";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated on Mon May 25 06:41:46 UTC 2026
|
# Generated on Mon Jun 8 06:51:27 UTC 2026
|
||||||
# This file contains all footprints available in the offical KiCAD library
|
# This file contains all footprints available in the offical KiCAD library
|
||||||
Audio_Module:Reverb_BTDR-1H
|
Audio_Module:Reverb_BTDR-1H
|
||||||
Audio_Module:Reverb_BTDR-1V
|
Audio_Module:Reverb_BTDR-1V
|
||||||
|
|
@ -12012,7 +12012,6 @@ Package_DFN_QFN:WDFN-8-1EP_4x3mm_P0.65mm_EP2.4x1.8mm_ThermalVias
|
||||||
Package_DFN_QFN:WDFN-8-1EP_6x5mm_P1.27mm_EP3.4x4mm
|
Package_DFN_QFN:WDFN-8-1EP_6x5mm_P1.27mm_EP3.4x4mm
|
||||||
Package_DFN_QFN:WDFN-8-1EP_8x6mm_P1.27mm_EP6x4.8mm
|
Package_DFN_QFN:WDFN-8-1EP_8x6mm_P1.27mm_EP6x4.8mm
|
||||||
Package_DFN_QFN:WDFN-8-1EP_8x6mm_P1.27mm_EP6x4.8mm_ThermalVias
|
Package_DFN_QFN:WDFN-8-1EP_8x6mm_P1.27mm_EP6x4.8mm_ThermalVias
|
||||||
Package_DFN_QFN:WDFN-8_2x2mm_P0.5mm
|
|
||||||
Package_DFN_QFN:WFDFPN-8-1EP_3x2mm_P0.5mm_EP1.25x1.35mm
|
Package_DFN_QFN:WFDFPN-8-1EP_3x2mm_P0.5mm_EP1.25x1.35mm
|
||||||
Package_DFN_QFN:WQFN-14-1EP_2.5x2.5mm_P0.5mm_EP1.45x1.45mm
|
Package_DFN_QFN:WQFN-14-1EP_2.5x2.5mm_P0.5mm_EP1.45x1.45mm
|
||||||
Package_DFN_QFN:WQFN-14-1EP_2.5x2.5mm_P0.5mm_EP1.45x1.45mm_ThermalVias
|
Package_DFN_QFN:WQFN-14-1EP_2.5x2.5mm_P0.5mm_EP1.45x1.45mm_ThermalVias
|
||||||
|
|
@ -12358,7 +12357,6 @@ Package_DirectFET:DirectFET_SQ
|
||||||
Package_DirectFET:DirectFET_ST
|
Package_DirectFET:DirectFET_ST
|
||||||
Package_LCC:Analog_LCC-8_5x5mm_P1.27mm
|
Package_LCC:Analog_LCC-8_5x5mm_P1.27mm
|
||||||
Package_LCC:MO047AD_PLCC-52_19.1x19.1mm_P1.27mm
|
Package_LCC:MO047AD_PLCC-52_19.1x19.1mm_P1.27mm
|
||||||
Package_LCC:PLCC-20
|
|
||||||
Package_LCC:PLCC-20_9.0x9.0mm_P1.27mm
|
Package_LCC:PLCC-20_9.0x9.0mm_P1.27mm
|
||||||
Package_LCC:PLCC-20_SMD-Socket
|
Package_LCC:PLCC-20_SMD-Socket
|
||||||
Package_LCC:PLCC-20_THT-Socket
|
Package_LCC:PLCC-20_THT-Socket
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated on Mon May 25 06:42:27 UTC 2026
|
# Generated on Mon Jun 8 06:52:04 UTC 2026
|
||||||
# This file contains all symbols available in the offical KiCAD library
|
# This file contains all symbols available in the offical KiCAD library
|
||||||
4xxx:14528
|
4xxx:14528
|
||||||
4xxx:14529
|
4xxx:14529
|
||||||
|
|
@ -2255,11 +2255,11 @@ Battery_Management:BQ76200PW
|
||||||
Battery_Management:BQ76920PW
|
Battery_Management:BQ76920PW
|
||||||
Battery_Management:BQ76930DBT
|
Battery_Management:BQ76930DBT
|
||||||
Battery_Management:BQ76940DBT
|
Battery_Management:BQ76940DBT
|
||||||
Battery_Management:BQ7695201PFBR
|
Battery_Management:BQ7695201PFB
|
||||||
Battery_Management:BQ7695202PFBR
|
Battery_Management:BQ7695202PFB
|
||||||
Battery_Management:BQ7695203PFBR
|
Battery_Management:BQ7695203PFB
|
||||||
Battery_Management:BQ7695204PFBR
|
Battery_Management:BQ7695204PFB
|
||||||
Battery_Management:BQ76952PFBR
|
Battery_Management:BQ76952PFB
|
||||||
Battery_Management:BQ78350DBT
|
Battery_Management:BQ78350DBT
|
||||||
Battery_Management:BQ78350DBT-R1
|
Battery_Management:BQ78350DBT-R1
|
||||||
Battery_Management:CN3063
|
Battery_Management:CN3063
|
||||||
|
|
@ -15115,6 +15115,7 @@ Memory_Flash:AM29F400Bx-xxEx
|
||||||
Memory_Flash:AM29F400Bx-xxSx
|
Memory_Flash:AM29F400Bx-xxSx
|
||||||
Memory_Flash:AM29PDL128G
|
Memory_Flash:AM29PDL128G
|
||||||
Memory_Flash:AT25DF041x-UxN-x
|
Memory_Flash:AT25DF041x-UxN-x
|
||||||
|
Memory_Flash:AT25SF041B-SSHD-X
|
||||||
Memory_Flash:AT25SF081-SSHD-X
|
Memory_Flash:AT25SF081-SSHD-X
|
||||||
Memory_Flash:AT25SF081-SSHF-X
|
Memory_Flash:AT25SF081-SSHF-X
|
||||||
Memory_Flash:AT25SF081-XMHD-X
|
Memory_Flash:AT25SF081-XMHD-X
|
||||||
|
|
@ -16037,6 +16038,7 @@ Power_Supervisor:TPS3831
|
||||||
Power_Supervisor:TPS3839DBZ
|
Power_Supervisor:TPS3839DBZ
|
||||||
Power_Supervisor:TPS3839DQN
|
Power_Supervisor:TPS3839DQN
|
||||||
RF:0900PC15J0013
|
RF:0900PC15J0013
|
||||||
|
RF:AD8302xRU
|
||||||
RF:ADC-10-1R
|
RF:ADC-10-1R
|
||||||
RF:ADCH-80
|
RF:ADCH-80
|
||||||
RF:ADCH-80A
|
RF:ADCH-80A
|
||||||
|
|
@ -16479,6 +16481,7 @@ RF_Module:DWM3000
|
||||||
RF_Module:E18-MS1-PCB
|
RF_Module:E18-MS1-PCB
|
||||||
RF_Module:E73-2G4M04S-52810
|
RF_Module:E73-2G4M04S-52810
|
||||||
RF_Module:E73-2G4M04S-52832
|
RF_Module:E73-2G4M04S-52832
|
||||||
|
RF_Module:ESP-01
|
||||||
RF_Module:ESP-07
|
RF_Module:ESP-07
|
||||||
RF_Module:ESP-12E
|
RF_Module:ESP-12E
|
||||||
RF_Module:ESP-12F
|
RF_Module:ESP-12F
|
||||||
|
|
|
||||||
1
public/media/.gitignore
vendored
1
public/media/.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
||||||
# Ignore everything except this .gitignore
|
# Ignore everything except this .gitignore
|
||||||
*
|
*
|
||||||
!.gitignore
|
!.gitignore
|
||||||
|
!.htaccess
|
||||||
|
|
|
||||||
10
public/media/.htaccess
Normal file
10
public/media/.htaccess
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Deny access to PHP and PHP-like files to prevent remote code execution
|
||||||
|
<FilesMatch "(?i)\.(php[3-8]?|phar|phtml|pht|phps)$">
|
||||||
|
<IfModule mod_authz_core.c>
|
||||||
|
Require all denied
|
||||||
|
</IfModule>
|
||||||
|
<IfModule !mod_authz_core.c>
|
||||||
|
Order deny,allow
|
||||||
|
Deny from all
|
||||||
|
</IfModule>
|
||||||
|
</FilesMatch>
|
||||||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
||||||
*/
|
*/
|
||||||
namespace App\Command;
|
namespace App\Command;
|
||||||
|
|
||||||
|
use App\Services\System\AppSecretChecker;
|
||||||
use Symfony\Component\Console\Attribute\AsCommand;
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
|
@ -33,7 +34,9 @@ use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;
|
||||||
#[AsCommand('partdb:check-requirements', 'Checks if the requirements Part-DB needs or recommends are fulfilled.')]
|
#[AsCommand('partdb:check-requirements', 'Checks if the requirements Part-DB needs or recommends are fulfilled.')]
|
||||||
class CheckRequirementsCommand extends Command
|
class CheckRequirementsCommand extends Command
|
||||||
{
|
{
|
||||||
public function __construct(protected ContainerBagInterface $params)
|
public function __construct(protected ContainerBagInterface $params,
|
||||||
|
private readonly AppSecretChecker $appSecretChecker
|
||||||
|
)
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
@ -121,6 +124,16 @@ class CheckRequirementsCommand extends Command
|
||||||
$io->success('Debug mode disabled.');
|
$io->success('Debug mode disabled.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Check if APP_SECRET has been changed from the default
|
||||||
|
if ($io->isVerbose()) {
|
||||||
|
$io->comment('Checking APP_SECRET...');
|
||||||
|
}
|
||||||
|
if ($this->appSecretChecker->isInsecureSecret()) {
|
||||||
|
$io->warning('APP_SECRET is set to the default value shipped with Part-DB. This is a security risk! Generate a new secret (e.g. using "openssl rand -hex 32") and set it as APP_SECRET in your .env.local file.');
|
||||||
|
} elseif (!$only_issues) {
|
||||||
|
$io->success('APP_SECRET has been changed from the default value.');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function checkPHPExtensions(SymfonyStyle $io, bool $only_issues = false): void
|
protected function checkPHPExtensions(SymfonyStyle $io, bool $only_issues = false): void
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ namespace App\Controller;
|
||||||
|
|
||||||
use App\DataTables\LogDataTable;
|
use App\DataTables\LogDataTable;
|
||||||
use App\Entity\Parts\Part;
|
use App\Entity\Parts\Part;
|
||||||
|
use App\Services\System\AppSecretChecker;
|
||||||
use App\Services\System\BannerHelper;
|
use App\Services\System\BannerHelper;
|
||||||
use App\Services\System\GitVersionInfoProvider;
|
use App\Services\System\GitVersionInfoProvider;
|
||||||
use App\Services\System\UpdateAvailableFacade;
|
use App\Services\System\UpdateAvailableFacade;
|
||||||
|
|
@ -36,8 +37,11 @@ use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
|
||||||
class HomepageController extends AbstractController
|
class HomepageController extends AbstractController
|
||||||
{
|
{
|
||||||
public function __construct(private readonly DataTableFactory $dataTable, private readonly BannerHelper $bannerHelper)
|
public function __construct(
|
||||||
{
|
private readonly DataTableFactory $dataTable,
|
||||||
|
private readonly BannerHelper $bannerHelper,
|
||||||
|
private readonly AppSecretChecker $appSecretChecker,
|
||||||
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -84,6 +88,8 @@ class HomepageController extends AbstractController
|
||||||
'new_version_available' => $updateAvailableManager->isUpdateAvailable(),
|
'new_version_available' => $updateAvailableManager->isUpdateAvailable(),
|
||||||
'new_version' => $updateAvailableManager->getLatestVersionString(),
|
'new_version' => $updateAvailableManager->getLatestVersionString(),
|
||||||
'new_version_url' => $updateAvailableManager->getLatestVersionUrl(),
|
'new_version_url' => $updateAvailableManager->getLatestVersionUrl(),
|
||||||
|
'insecure_app_secret' => $this->appSecretChecker->isInsecureSecret(),
|
||||||
|
'suggested_app_secret' => $this->appSecretChecker->isInsecureSecret() ? $this->appSecretChecker->generateSecret() : null,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ class PartImportExportController extends AbstractController
|
||||||
goto ret;
|
goto ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($errors) || $errors) {
|
if (!isset($errors) || $errors) { //@phpstan-ignore-line
|
||||||
$this->addFlash('error', 'parts.import.flash.error');
|
$this->addFlash('error', 'parts.import.flash.error');
|
||||||
} else {
|
} else {
|
||||||
$this->addFlash('success', 'parts.import.flash.success');
|
$this->addFlash('success', 'parts.import.flash.success');
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ class AttachmentSubmitHandler
|
||||||
|
|
||||||
protected const BLACKLISTED_EXTENSIONS = ['php', 'phtml', 'php3', 'ph3', 'php4', 'ph4', 'php5', 'ph5', 'phtm', 'sh',
|
protected const BLACKLISTED_EXTENSIONS = ['php', 'phtml', 'php3', 'ph3', 'php4', 'ph4', 'php5', 'ph5', 'phtm', 'sh',
|
||||||
'asp', 'cgi', 'py', 'pl', 'exe', 'aspx', 'js', 'mjs', 'jsp', 'css', 'jar', 'html', 'htm', 'shtm', 'shtml', 'htaccess',
|
'asp', 'cgi', 'py', 'pl', 'exe', 'aspx', 'js', 'mjs', 'jsp', 'css', 'jar', 'html', 'htm', 'shtm', 'shtml', 'htaccess',
|
||||||
'htpasswd', ''];
|
'htpasswd', 'phar', 'phps', ''];
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected AttachmentPathResolver $pathResolver,
|
protected AttachmentPathResolver $pathResolver,
|
||||||
|
|
|
||||||
|
|
@ -169,8 +169,8 @@ class LogEntryExtraFormatter
|
||||||
$array['log.collection_deleted.deleted'] = sprintf(
|
$array['log.collection_deleted.deleted'] = sprintf(
|
||||||
'%s: %s (%s)',
|
'%s: %s (%s)',
|
||||||
$this->elementTypeNameGenerator->getLocalizedTypeLabel($context->getDeletedElementClass()),
|
$this->elementTypeNameGenerator->getLocalizedTypeLabel($context->getDeletedElementClass()),
|
||||||
$context->getOldName() ?? (string) $context->getDeletedElementID(),
|
htmlspecialchars($context->getOldName() ?? (string) $context->getDeletedElementID()),
|
||||||
$context->getCollectionName()
|
htmlspecialchars($context->getCollectionName())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
63
src/Services/System/AppSecretChecker.php
Normal file
63
src/Services/System/AppSecretChecker.php
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 - 2024 Jan Böhmer (https://github.com/jbtronics)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published
|
||||||
|
* by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Services\System;
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether APP_SECRET has been changed from the default value shipped with Part-DB.
|
||||||
|
*/
|
||||||
|
final readonly class AppSecretChecker
|
||||||
|
{
|
||||||
|
/** Known default/example secrets that must not be used in production. */
|
||||||
|
public const INSECURE_SECRETS = [
|
||||||
|
'a03498528f5a5fc089273ec9ae5b2849', // default in .env
|
||||||
|
'318b5d659e07a0b3f96d9b3a83b254ca', // default in .env.dev
|
||||||
|
'CHANGE_ME' //example secret used in documentation and error messages
|
||||||
|
];
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
#[Autowire('%kernel.secret%')]
|
||||||
|
private string $appSecret,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool True if the app secret is one of the known insecure default secrets, false otherwise.
|
||||||
|
*/
|
||||||
|
public function isInsecureSecret(): bool
|
||||||
|
{
|
||||||
|
return in_array($this->appSecret, self::INSECURE_SECRETS, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a new random app secret that can be used to replace the default insecure one.
|
||||||
|
* @return string
|
||||||
|
* @throws \Random\RandomException
|
||||||
|
*/
|
||||||
|
public function generateSecret(): string
|
||||||
|
{
|
||||||
|
//Symfony docs recommend 32 characters for the app secret, which are 16 random bytes when hex-encoded.
|
||||||
|
return bin2hex(random_bytes(16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -85,6 +85,16 @@
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
{% if insecure_app_secret and is_granted('@system.server_infos') %}
|
||||||
|
<div class="alert alert-warning" role="alert">
|
||||||
|
<h5><i class="fa-solid fa-triangle-exclamation fa-fw"></i> {% trans %}system.app_secret.insecure.title{% endtrans %}</h5>
|
||||||
|
<p class="mb-1">{% trans %}system.app_secret.insecure.message{% endtrans %}</p>
|
||||||
|
<p class="mb-0">{% trans %}system.app_secret.insecure.suggestion{% endtrans %}
|
||||||
|
<br><code>APP_SECRET={{ suggested_app_secret }}</code></p>
|
||||||
|
<small>{% trans %}update_manager.new_version_available.only_administrators_can_see{% endtrans %}</small>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if is_granted('@system.show_updates') %}
|
{% if is_granted('@system.show_updates') %}
|
||||||
{{ nv.new_version_alert(new_version_available, new_version, new_version_url) }}
|
{{ nv.new_version_alert(new_version_available, new_version, new_version_url) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
<unit id="KSFhj_3" name="currency.iso_code.caption">
|
<unit id="KSFhj_3" name="currency.iso_code.caption">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>currency.iso_code.caption</source>
|
<source>currency.iso_code.caption</source>
|
||||||
<target>ISO Code</target>
|
<target>ISO-Code</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="UqMuNZQ" name="currency.symbol.caption">
|
<unit id="UqMuNZQ" name="currency.symbol.caption">
|
||||||
|
|
@ -13647,5 +13647,23 @@ Buerklin-API-Authentication-Server:
|
||||||
<target>Aktiviert das Browser-Plugin für diese Instanz.</target>
|
<target>Aktiviert das Browser-Plugin für diese Instanz.</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="JqcvhX_" name="system.app_secret.insecure.title">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>system.app_secret.insecure.title</source>
|
||||||
|
<target>Unsicheres APP_SECRET</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="XSSYWTJ" name="system.app_secret.insecure.message">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>system.app_secret.insecure.message</source>
|
||||||
|
<target>Die Umgebungsvariable <code>APP_SECRET</code> ist auf den Standardwert gesetzt, der mit Part-DB ausgeliefert wird. Dies stellt ein Sicherheitsrisiko dar! Setzen Sie sie in Ihrer Datei <code>.env.local</code> oder <code>docker-compose.yaml</code> auf einen neuen Zufallswert.</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="e7.f3m0" name="system.app_secret.insecure.suggestion">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>system.app_secret.insecure.suggestion</source>
|
||||||
|
<target>Sie können diesen zufällig generierten Wert verwenden (geben Sie ihn niemandem weiter):</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|
|
||||||
|
|
@ -13649,5 +13649,23 @@ Buerklin-API Authentication server:
|
||||||
<target>When enabled users with the info provider permission can submit pages to Part-DB and retrieve them later.</target>
|
<target>When enabled users with the info provider permission can submit pages to Part-DB and retrieve them later.</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="JqcvhX_" name="system.app_secret.insecure.title">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>system.app_secret.insecure.title</source>
|
||||||
|
<target>Insecure APP_SECRET</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="XSSYWTJ" name="system.app_secret.insecure.message">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>system.app_secret.insecure.message</source>
|
||||||
|
<target>The <code>APP_SECRET</code> environment variable is set to the default value shipped with Part-DB. This is a security risk! Set it to a new random value in your <code>.env.local</code> or <code>docker-compose.yaml</code> file.</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="e7.f3m0" name="system.app_secret.insecure.suggestion">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>system.app_secret.insecure.suggestion</source>
|
||||||
|
<target>You can use this randomly generated value (share it with nobody):</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue