Compare commits

...

16 commits

Author SHA1 Message Date
github-actions[bot]
3db982b60e Update KiCad symbols and footprints lists
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
Docker Image Build / merge (push) Has been cancelled
Docker Image Build (FrankenPHP) / merge (push) Has been cancelled
2026-06-08 06:52:55 +00:00
Jan Böhmer
57a0dfdbdb Fixed phpstan issue
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
Docker Image Build / merge (push) Has been cancelled
Docker Image Build (FrankenPHP) / merge (push) Has been cancelled
2026-06-07 22:49:41 +02:00
Jan Böhmer
61dcc99597
New Crowdin updates (#1383)
* New translations messages.en.xlf (German)

[ci skip]

* New translations messages.en.xlf (German)

[ci skip]

* New translations messages.en.xlf (German)

[ci skip]

* New translations messages.en.xlf (English)

[ci skip]

* New translations messages.en.xlf (German)

[ci skip]

* New translations messages.en.xlf (English)

[ci skip]
2026-06-07 22:47:22 +02:00
Jan Böhmer
cf8826a906 Bumped version to 2.12.1 2026-06-07 22:43:33 +02:00
Jan Böhmer
4b00541dd6 Improved APP_SECRET warning message 2026-06-07 22:43:06 +02:00
Jan Böhmer
93ab410857 Added documentation about changing the APP_SECRET env on installation 2026-06-07 22:37:47 +02:00
Jan Böhmer
cb28afcdf5 Moved APP_SECRET value to the top of .env 2026-06-07 22:28:29 +02:00
Jan Böhmer
f888e10827 Show a warning if using the default APP_SECRET value 2026-06-07 22:26:45 +02:00
Jan Böhmer
c229208bd5 Rename phar files on upload
Some checks are pending
Build assets artifact / Build assets artifact (push) Waiting to run
Docker Image Build / build (linux/amd64, amd64, ubuntu-latest) (push) Waiting to run
Docker Image Build / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Waiting to run
Docker Image Build / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Waiting to run
Docker Image Build / merge (push) Blocked by required conditions
Docker Image Build (FrankenPHP) / build (linux/amd64, amd64, ubuntu-latest) (push) Waiting to run
Docker Image Build (FrankenPHP) / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Waiting to run
Docker Image Build (FrankenPHP) / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Waiting to run
Docker Image Build (FrankenPHP) / merge (push) Blocked by required conditions
Static analysis / Static analysis (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Waiting to run
2026-06-07 20:45:43 +02:00
Jan Böhmer
6e5d1c967f Block access to all php and phar files that are uploaded into the media folder 2026-06-07 20:40:15 +02:00
tonghuaroot
c2ec0ee12b Escape user-controlled element/collection names in CollectionElementDeleted log rendering
LogEntryExtraFormatter::getInternalFormat() escapes user-controlled
strings with htmlspecialchars() in every branch except the
CollectionElementDeleted one, which interpolates getOldName() and
getCollectionName() into the returned HTML unescaped. That string is
rendered as raw HTML by LogEntryExtraColumn in the activity-log and
element-history DataTables, so a name set on a deleted sub-element
(parameter/attachment/lot/orderdetail) by a low-privileged editor is
parsed as live markup in a log viewer's browser (stored XSS / HTML
injection).

Wrap both values in htmlspecialchars(), matching the sibling branches
(e.g. ElementDeletedLogEntry at the old_name line).
2026-06-07 18:04:40 +02:00
Jan Böhmer
6ae4381551 Fixed phpstan issues 2026-06-07 14:11:53 +02:00
Jan Böhmer
e018e1d821 Merge remote-tracking branch 'origin/master' 2026-06-07 14:08:48 +02:00
Jan Böhmer
4b6a3ba72b Updated dependencies 2026-06-07 14:08:46 +02:00
Jan Böhmer
c547500031
Update KiCad symbols and footprints lists (#1395)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-07 14:08:00 +02:00
Jan Böhmer
4b119490ca Updated depdencies
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
Docker Image Build / merge (push) Has been cancelled
Docker Image Build (FrankenPHP) / merge (push) Has been cancelled
2026-06-03 22:49:22 +02:00
24 changed files with 1330 additions and 1114 deletions

View file

@ -51,5 +51,9 @@
# Disable Topics tracking if not enabled explicitly: https://github.com/jkarlin/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
}

View file

@ -15,6 +15,14 @@
AllowOverride All
</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,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular

5
.env
View file

@ -1,6 +1,10 @@
#### Part-DB Configuration
# 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
###################################################################################
@ -158,7 +162,6 @@ CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$'
###> symfony/framework-bundle ###
APP_ENV=prod
APP_SECRET=a03498528f5a5fc089273ec9ae5b2849
APP_SHARE_DIR=var/share
###< symfony/framework-bundle ###

View file

@ -1 +1 @@
2.12.0
2.12.1

819
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -2436,6 +2436,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* },
* 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
* 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{
* enabled?: bool|Param, // Default: true

View file

@ -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, ...)
* `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.
* `APP_SECRET` (env only): This variable is a configuration parameter used for various security-related purposes,
particularly for securing and protecting various aspects of your application. It's a secret key that is used for
cryptographic operations and security measures (session management, CSRF protection, etc..). Therefore this
value should be handled as confidential data and not shared publicly.
* `APP_SECRET` (env only): A secret key used by Symfony for cryptographic operations — signing cookies, generating
CSRF tokens, and other security-sensitive tasks. **You must change this from the default value before exposing
Part-DB to any network.** The default value shipped with Part-DB is publicly known; leaving it in place would allow
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
part image gallery
* `IPN_SUGGEST_REGEX`: A global regular expression, that part IPNs have to fulfill. Enforce your own format for your users.

View file

@ -47,7 +47,10 @@ services:
- DATABASE_URL=sqlite:///%kernel.project_dir%/var/db/app.db
# In docker env logs will be redirected to stderr
- 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
# 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.
@ -89,7 +92,11 @@ services:
4. Customize the settings by changing the environment variables (or adding new ones). See [Configuration]({% link
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
docker-compose up -d
@ -100,7 +107,7 @@ services:
> 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
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
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
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 }
> 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.
> Generate a random string for APP_SECRET.
```yaml
version: '3.3'
@ -142,14 +150,19 @@ services:
environment:
# Replace SECRET_USER_PASSWORD with the value of MYSQL_PASSWORD from below
- 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
- APP_ENV=docker
# 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/
# 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!
# - DB_AUTOMIGRATE=true
# 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/
# 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!
# - DB_AUTOMIGRATE=true
# You can configure Part-DB using the webUI or environment variables
# However you can add any other environment configuration you want here

View file

@ -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.
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
this can not be changed after creating price information.

View file

@ -52,6 +52,11 @@ server {
location ~ \.php$ {
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
location ~* \.svg$ {

View file

@ -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
Audio_Module:Reverb_BTDR-1H
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_8x6mm_P1.27mm_EP6x4.8mm
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: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
@ -12358,7 +12357,6 @@ Package_DirectFET:DirectFET_SQ
Package_DirectFET:DirectFET_ST
Package_LCC:Analog_LCC-8_5x5mm_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_SMD-Socket
Package_LCC:PLCC-20_THT-Socket

View file

@ -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
4xxx:14528
4xxx:14529
@ -2255,11 +2255,11 @@ Battery_Management:BQ76200PW
Battery_Management:BQ76920PW
Battery_Management:BQ76930DBT
Battery_Management:BQ76940DBT
Battery_Management:BQ7695201PFBR
Battery_Management:BQ7695202PFBR
Battery_Management:BQ7695203PFBR
Battery_Management:BQ7695204PFBR
Battery_Management:BQ76952PFBR
Battery_Management:BQ7695201PFB
Battery_Management:BQ7695202PFB
Battery_Management:BQ7695203PFB
Battery_Management:BQ7695204PFB
Battery_Management:BQ76952PFB
Battery_Management:BQ78350DBT
Battery_Management:BQ78350DBT-R1
Battery_Management:CN3063
@ -15115,6 +15115,7 @@ Memory_Flash:AM29F400Bx-xxEx
Memory_Flash:AM29F400Bx-xxSx
Memory_Flash:AM29PDL128G
Memory_Flash:AT25DF041x-UxN-x
Memory_Flash:AT25SF041B-SSHD-X
Memory_Flash:AT25SF081-SSHD-X
Memory_Flash:AT25SF081-SSHF-X
Memory_Flash:AT25SF081-XMHD-X
@ -16037,6 +16038,7 @@ Power_Supervisor:TPS3831
Power_Supervisor:TPS3839DBZ
Power_Supervisor:TPS3839DQN
RF:0900PC15J0013
RF:AD8302xRU
RF:ADC-10-1R
RF:ADCH-80
RF:ADCH-80A
@ -16479,6 +16481,7 @@ RF_Module:DWM3000
RF_Module:E18-MS1-PCB
RF_Module:E73-2G4M04S-52810
RF_Module:E73-2G4M04S-52832
RF_Module:ESP-01
RF_Module:ESP-07
RF_Module:ESP-12E
RF_Module:ESP-12F

View file

@ -1,3 +1,4 @@
# Ignore everything except this .gitignore
*
!.gitignore
!.gitignore
!.htaccess

10
public/media/.htaccess Normal file
View 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>

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
*/
namespace App\Command;
use App\Services\System\AppSecretChecker;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
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.')]
class CheckRequirementsCommand extends Command
{
public function __construct(protected ContainerBagInterface $params)
public function __construct(protected ContainerBagInterface $params,
private readonly AppSecretChecker $appSecretChecker
)
{
parent::__construct();
}
@ -121,6 +124,16 @@ class CheckRequirementsCommand extends Command
$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

View file

@ -24,6 +24,7 @@ namespace App\Controller;
use App\DataTables\LogDataTable;
use App\Entity\Parts\Part;
use App\Services\System\AppSecretChecker;
use App\Services\System\BannerHelper;
use App\Services\System\GitVersionInfoProvider;
use App\Services\System\UpdateAvailableFacade;
@ -36,8 +37,11 @@ use Symfony\Component\Routing\Attribute\Route;
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' => $updateAvailableManager->getLatestVersionString(),
'new_version_url' => $updateAvailableManager->getLatestVersionUrl(),
'insecure_app_secret' => $this->appSecretChecker->isInsecureSecret(),
'suggested_app_secret' => $this->appSecretChecker->isInsecureSecret() ? $this->appSecretChecker->generateSecret() : null,
]);
}
}

View file

@ -90,7 +90,7 @@ class PartImportExportController extends AbstractController
goto ret;
}
if (!isset($errors) || $errors) {
if (!isset($errors) || $errors) { //@phpstan-ignore-line
$this->addFlash('error', 'parts.import.flash.error');
} else {
$this->addFlash('success', 'parts.import.flash.success');

View file

@ -69,7 +69,7 @@ class AttachmentSubmitHandler
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',
'htpasswd', ''];
'htpasswd', 'phar', 'phps', ''];
public function __construct(
protected AttachmentPathResolver $pathResolver,

View file

@ -169,8 +169,8 @@ class LogEntryExtraFormatter
$array['log.collection_deleted.deleted'] = sprintf(
'%s: %s (%s)',
$this->elementTypeNameGenerator->getLocalizedTypeLabel($context->getDeletedElementClass()),
$context->getOldName() ?? (string) $context->getDeletedElementID(),
$context->getCollectionName()
htmlspecialchars($context->getOldName() ?? (string) $context->getDeletedElementID()),
htmlspecialchars($context->getCollectionName())
);
}
@ -218,4 +218,4 @@ class LogEntryExtraFormatter
return implode(', ', $output);
}
}
}

View 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));
}
}

View file

@ -85,6 +85,16 @@
{% 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') %}
{{ nv.new_version_alert(new_version_available, new_version, new_version_url) }}
{% endif %}

View file

@ -64,7 +64,7 @@
<unit id="KSFhj_3" name="currency.iso_code.caption">
<segment state="translated">
<source>currency.iso_code.caption</source>
<target>ISO Code</target>
<target>ISO-Code</target>
</segment>
</unit>
<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>
</segment>
</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 &lt;code&gt;APP_SECRET&lt;/code&gt; ist auf den Standardwert gesetzt, der mit Part-DB ausgeliefert wird. Dies stellt ein Sicherheitsrisiko dar! Setzen Sie sie in Ihrer Datei &lt;code&gt;.env.local&lt;/code&gt; oder &lt;code&gt;docker-compose.yaml&lt;/code&gt; 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>
</xliff>

View file

@ -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>
</segment>
</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 &lt;code&gt;APP_SECRET&lt;/code&gt; 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 &lt;code&gt;.env.local&lt;/code&gt; or &lt;code&gt;docker-compose.yaml&lt;/code&gt; 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>
</xliff>

1361
yarn.lock

File diff suppressed because it is too large Load diff