Compare commits

...

4 Commits

Author SHA1 Message Date
Jacek
b1a15b4895 docs: changelog ver_0.334 - poprawki bezpieczenstwa
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 09:19:15 +01:00
Jacek
167b11679d security: faza 1 - usuniecie debug logu tpay, naprawa SQL i usun rb.php
- ShopOrderController: usunieto file_put_contents do tpay.txt (ujawnial dane platnicze)
- ShopOrderController: hardcoded sekret HotPay przeniesiony do stałej HOTPAY_HASH_SEED
- IntegrationsRepository: zastapiono raw SQL query('SELECT * FROM $table') metodą Medoo select()
- index.php + admin/index.php: usunieto RedBeanPHP (rb.php) - biblioteka byla ladowana ale nieuzywana
- libraries/rb.php: usunieto plik (536 KB, zero uzyc w kodzie aplikacji)
- Testy IntegrationsRepository zaktualizowane do nowego API (select zamiast query)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 09:18:37 +01:00
Jacek
f268e3b5d4 feat: update workflow documentation and add release process steps 2026-03-10 23:33:52 +01:00
Jacek
3e073d2719 build: ver_0.333 - ochrona przed podwójnym składaniem zamówienia
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 21:50:58 +01:00
17 changed files with 277 additions and 17682 deletions

View File

@@ -0,0 +1,86 @@
# shopPRO — Koniec Pracy (release workflow)
Execute the full release workflow for shopPRO. This is a sequential pipeline — each step depends on the previous one succeeding. Stop and report if any step fails.
## Step 1: Run tests
Run the full PHPUnit test suite:
```bash
php phpunit.phar
```
All tests must pass. If any test fails, stop here — do not proceed to commit. Report the failures and wait for instructions.
## Step 2: Determine version
Read the latest git tag to determine the current version number:
```bash
git tag --sort=-v:refname | head -1
```
The new version is the previous version incremented by 1 (e.g., v0.333 → v0.334). Use this version number throughout the remaining steps.
## Step 3: Update documentation
Update these docs files **only if** changes in this session affect them:
| File | When to update |
|------|---------------|
| `docs/CHANGELOG.md` | Always — add a new version entry at the top describing what changed |
| `docs/TESTING.md` | If tests were added/removed — update test count and structure |
| `CLAUDE.md` | If test count changed — update the "Current suite" line |
| `docs/DATABASE_STRUCTURE.md` | If database schema changed |
| `docs/PROJECT_STRUCTURE.md` | If architecture/files changed significantly |
| `docs/FORM_EDIT_SYSTEM.md` | If form system was modified |
## Step 4: SQL migrations
If database schema changes were made, create a migration file at `migrations/{version}.sql` (e.g., `migrations/0.334.sql`). Do NOT put SQL files in `updates/` — the build script reads from `migrations/` automatically.
If no DB changes were made, skip this step.
## Step 5: Commit
Stage all relevant changed files (source code, templates, tests, docs, migrations) and commit with a descriptive message. Do NOT stage `.serena/`, `.env`, or credentials files.
Use this commit message format:
```
feat/fix/refactor: concise description of what changed
Longer explanation if needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
```
## Step 6: Push
```bash
git push
```
## Step 7: Build update package
Tag the new version and run the build script:
```bash
git tag v0.{VERSION}
powershell.exe -ExecutionPolicy Bypass -File build-update.ps1 -FromTag v0.{PREV_VERSION} -ToTag v0.{VERSION} -ChangelogEntry "{changelog_description}"
```
The `{changelog_description}` should be a short Polish description of the changes (matching the CHANGELOG entry).
## Step 8: Commit and push the package
Stage the generated update files and commit:
```bash
git add updates/0.30/ver_0.{VERSION}.zip updates/0.30/ver_0.{VERSION}_manifest.json updates/versions.php updates/changelog-data.html
git commit -m "build: ver_0.{VERSION} - {short_description}"
git push
git push origin v0.{VERSION}
```
## Step 9: Report summary
Print a summary:
- Version number
- Test results (count, assertions)
- Files changed
- Commit hashes
- Update package path
- Tag name

View File

@@ -127,3 +127,8 @@ language_backend:
# list of regex patterns which, when matched, mark a memory entry as readonly.
# Extends the list from the global configuration, merging the two lists.
read_only_memory_patterns: []
# line ending convention to use when writing source files.
# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default)
# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings.
line_ending:

View File

@@ -217,18 +217,11 @@ $controller = new \admin\Controllers\ExampleController($repo);
- AAA pattern: Arrange, Act, Assert
- Tests mirror source structure: `tests/Unit/Domain/{Module}/{Class}Test.php`
## Workflow (AGENTS.md)
## Workflow
When user says **"KONIEC PRACY"**, execute in order:
1. Run tests
2. Update documentation if needed: `docs/DATABASE_STRUCTURE.md`, `docs/PROJECT_STRUCTURE.md`, `docs/FORM_EDIT_SYSTEM.md`, `docs/CHANGELOG.md`, `docs/TESTING.md`
3. SQL migrations (if DB changes): place in `migrations/{version}.sql` (e.g. `migrations/0.304.sql`). **NOT** in `updates/` — build script reads from `migrations/` automatically
4. Commit
5. Push
6. Build update package: `git tag v0.XXX && powershell.exe -ExecutionPolicy Bypass -File build-update.ps1 -FromTag v0.PREV -ToTag v0.XXX -ChangelogEntry "opis"` — skrypt automatycznie aktualizuje `versions.php`
7. Commit i push plików paczki (`updates/0.30/ver_0.XXX.zip`, `ver_0.XXX_manifest.json`, `updates/versions.php`, `updates/changelog-data.html`)
When user says **"KONIEC PRACY"**, run `/koniec-pracy` (see `.claude/commands/koniec-pracy.md`).
Before starting implementation, review current state of docs (see AGENTS.md for full list).
Before starting implementation, review current state of docs.
## Key Documentation
- `docs/MEMORY.md` — project memory: known issues, confirmed patterns, ORM pitfalls, caching conventions

View File

@@ -217,18 +217,11 @@ $controller = new \admin\Controllers\ExampleController($repo);
- AAA pattern: Arrange, Act, Assert
- Tests mirror source structure: `tests/Unit/Domain/{Module}/{Class}Test.php`
## Workflow (AGENTS.md)
## Workflow
When user says **"KONIEC PRACY"**, execute in order:
1. Run tests
2. Update documentation if needed: `docs/DATABASE_STRUCTURE.md`, `docs/PROJECT_STRUCTURE.md`, `docs/FORM_EDIT_SYSTEM.md`, `docs/CHANGELOG.md`, `docs/TESTING.md`
3. SQL migrations (if DB changes): place in `migrations/{version}.sql` (e.g. `migrations/0.304.sql`). **NOT** in `updates/` — build script reads from `migrations/` automatically
4. Commit
5. Push
6. Build update package: `git tag v0.XXX && powershell.exe -ExecutionPolicy Bypass -File build-update.ps1 -FromTag v0.PREV -ToTag v0.XXX -ChangelogEntry "opis"` — skrypt automatycznie aktualizuje `versions.php`
7. Commit i push plików paczki (`updates/0.30/ver_0.XXX.zip`, `ver_0.XXX_manifest.json`, `updates/versions.php`, `updates/changelog-data.html`)
When user says **"KONIEC PRACY"**, run `/koniec-pracy` (see `.claude/commands/koniec-pracy.md`).
Before starting implementation, review current state of docs (see AGENTS.md for full list).
Before starting implementation, review current state of docs.
## Key Documentation
- `docs/MEMORY.md` — project memory: known issues, confirmed patterns, ORM pitfalls, caching conventions

View File

@@ -31,17 +31,9 @@ function __autoload_my_classes( $classname )
spl_autoload_register( '__autoload_my_classes' );
require_once '../config.php';
require_once '../libraries/medoo/medoo.php';
require_once '../libraries/rb.php';
require_once '../libraries/phpmailer/class.phpmailer.php';
require_once '../libraries/phpmailer/class.smtp.php';
define( 'REDBEAN_MODEL_PREFIX', '' );
\R::setup( 'mysql:host=' . $database['host'] . ';dbname=' . $database['name'], $database['user'], $database['password'] );
\R::ext( 'xdispense', function ( $type )
{
return R::getRedBean() -> dispense( $type );
} );
date_default_timezone_set( 'Europe/Warsaw' );
$mdb = new medoo( [

View File

@@ -28,10 +28,9 @@ class IntegrationsRepository
public function getSettings( string $provider ): array
{
$table = $this->settingsTable( $provider );
$stmt = $this->db->query( "SELECT * FROM $table" );
$results = $stmt ? $stmt->fetchAll( \PDO::FETCH_ASSOC ) : [];
$rows = $this->db->select( $table, [ 'name', 'value' ] );
$settings = [];
foreach ( $results as $row )
foreach ( $rows ?: [] as $row )
$settings[$row['name']] = $row['value'];
return $settings;

View File

@@ -6,6 +6,8 @@ use Domain\Order\OrderAdminService;
class ShopOrderController
{
private const HOTPAY_HASH_SEED = 'ProjectPro1916;';
private $repository;
private $adminService;
@@ -29,8 +31,6 @@ class ShopOrderController
public function paymentStatusTpay()
{
file_put_contents( 'tpay.txt', print_r( $_POST, true ) . print_r( $_GET, true ), FILE_APPEND );
if ( \Shared\Helpers\Helpers::get( 'tr_status' ) == 'TRUE' && \Shared\Helpers\Helpers::get( 'tr_crc' ) )
{
$order = $this->repository->findRawByHash( \Shared\Helpers\Helpers::get( 'tr_crc' ) );
@@ -102,7 +102,7 @@ class ShopOrderController
$summary_tmp += $order['transport_cost'];
endif;
if ( hash( "sha256", "ProjectPro1916;" . round( $summary_tmp, 2 ) . ";" . $_POST["ID_PLATNOSCI"] . ";" . $_POST["ID_ZAMOWIENIA"] . ";" . $_POST["STATUS"] . ";" . $_POST["SEKRET"] ) == $_POST["HASH"] )
if ( hash( "sha256", self::HOTPAY_HASH_SEED . round( $summary_tmp, 2 ) . ";" . $_POST["ID_PLATNOSCI"] . ";" . $_POST["ID_ZAMOWIENIA"] . ";" . $_POST["STATUS"] . ";" . $_POST["SEKRET"] ) == $_POST["HASH"] )
{
if ( $_POST["STATUS"] == "SUCCESS" )
{

View File

@@ -4,6 +4,17 @@ Logi zmian z migracji na Domain-Driven Architecture. Najnowsze na gorze.
---
## ver. 0.334 (2026-03-12) - Poprawki bezpieczeństwa: debug log, SQL, RedBeanPHP
- **SECURITY**: `ShopOrderController::paymentStatusTpay()` — usunięto `file_put_contents('tpay.txt', ...)` który logował pełne dane POST/GET płatności do publicznego pliku
- **SECURITY**: `ShopOrderController` — hardcoded sekret HotPay `"ProjectPro1916;"` przeniesiony do prywatnej stałej `HOTPAY_HASH_SEED`
- **SECURITY**: `IntegrationsRepository::getSettings()` — zastąpiono raw `query("SELECT * FROM $table")` metodą Medoo `select()` (spójne z zasadą braku string concatenation w SQL)
- **REFACTOR**: `index.php`, `admin/index.php` — usunięto RedBeanPHP (`rb.php`): biblioteka była ładowana i inicjalizowana, ale nigdy nie używana w żadnym zapytaniu
- **CLEANUP**: `libraries/rb.php` — usunięto plik (536 KB zbędnych zależności)
- **TESTS**: `IntegrationsRepositoryTest` — zaktualizowano 6 testów do nowego API (`select` zamiast `query` dla `getSettings`)
---
## ver. 0.333 (2026-03-10) - Ochrona przed podwójnym składaniem zamówienia (order submit token)
- **NEW**: `ShopBasketController` — mechanizm tokenu CSRF chroniący przed podwójnym składaniem zamówienia (generowanie, walidacja, konsumpcja tokenu w sesji)

View File

@@ -4,4 +4,5 @@ naprawić działanie newslettera i zapis do bazy newslettera
program lojalnościowy
proponowane produkty w koszyku
Do zamówień w statusie: realizowane lub oczekuje na wpłatę. Opcja tylko dla zarejestrowanych klientów. https://royal-stone.pl/pl/order1.html
Dodać możliwość ustawienia limitu znaków w wiadomościach do produktu
Dodać możliwość ustawienia limitu znaków w wiadomościach do produktu
8. [] Przerobić analitykę Google Analytics i Google ADS

View File

@@ -22,17 +22,9 @@ date_default_timezone_set( 'Europe/Warsaw' );
require_once 'config.php';
require_once 'libraries/medoo/medoo.php';
require_once 'libraries/rb.php';
require_once 'libraries/phpmailer/class.phpmailer.php';
require_once 'libraries/phpmailer/class.smtp.php';
\R::setup( 'mysql:host=' . $database[ 'host' ] . ';dbname=' . $database[ 'name' ], $database[ 'user' ], $database[ 'password' ] );
\R::ext( 'xdispense', function ( $type )
{
return R::getRedBean() -> dispense( $type );
} );
$pdo = \R::getPDO();
session_start();
if ( !isset( $_SESSION[ 'check' ] ) )

File diff suppressed because it is too large Load Diff

View File

@@ -82,7 +82,7 @@
<? endforeach;?>
<div class="hr"></div>
<div class="basket-summary">
Wartość koszyka: 1
Wartość koszyka:
<span>
<?= \Shared\Helpers\Helpers::decimal( $summary );?> zł
</span>

View File

@@ -17,20 +17,14 @@ class IntegrationsRepositoryTest extends TestCase
public function testGetSettingsReturnsArray(): void
{
$stmt = $this->createMock(\PDOStatement::class);
$stmt->expects($this->once())
->method('fetchAll')
->with(\PDO::FETCH_ASSOC)
$this->mockDb->expects($this->once())
->method('select')
->with('pp_shop_apilo_settings', ['name', 'value'])
->willReturn([
['name' => 'client-id', 'value' => 'abc123'],
['name' => 'client-secret', 'value' => 'secret'],
]);
$this->mockDb->expects($this->once())
->method('query')
->with('SELECT * FROM pp_shop_apilo_settings')
->willReturn($stmt);
$settings = $this->repository->getSettings('apilo');
$this->assertIsArray($settings);
@@ -144,10 +138,7 @@ class IntegrationsRepositoryTest extends TestCase
public function testApiloGetAccessTokenReturnsNullWithoutSettings(): void
{
$stmt = $this->createMock(\PDOStatement::class);
$stmt->method('fetchAll')->willReturn([]);
$this->mockDb->method('query')->willReturn($stmt);
$this->mockDb->method('select')->willReturn([]);
$this->assertNull($this->repository->apiloGetAccessToken());
}
@@ -184,16 +175,10 @@ class IntegrationsRepositoryTest extends TestCase
public function testApiloFetchListResultReturnsDetailedErrorWhenConfigMissing(): void
{
$stmt = $this->createMock(\PDOStatement::class);
$stmt->expects($this->once())
->method('fetchAll')
->with(\PDO::FETCH_ASSOC)
->willReturn([]);
$this->mockDb->expects($this->once())
->method('query')
->with('SELECT * FROM pp_shop_apilo_settings')
->willReturn($stmt);
->method('select')
->with('pp_shop_apilo_settings', ['name', 'value'])
->willReturn([]);
$result = $this->repository->apiloFetchListResult('payment');
@@ -204,16 +189,10 @@ class IntegrationsRepositoryTest extends TestCase
public function testApiloIntegrationStatusReturnsMissingConfigMessage(): void
{
$stmt = $this->createMock(\PDOStatement::class);
$stmt->expects($this->once())
->method('fetchAll')
->with(\PDO::FETCH_ASSOC)
->willReturn([]);
$this->mockDb->expects($this->once())
->method('query')
->with('SELECT * FROM pp_shop_apilo_settings')
->willReturn($stmt);
->method('select')
->with('pp_shop_apilo_settings', ['name', 'value'])
->willReturn([]);
$status = $this->repository->apiloIntegrationStatus();
@@ -242,25 +221,20 @@ class IntegrationsRepositoryTest extends TestCase
public function testSettingsTableMapping(): void
{
// Verify apilo maps correctly
$stmt = $this->createMock(\PDOStatement::class);
$stmt->method('fetchAll')->willReturn([]);
$this->mockDb->method('query')
->with($this->stringContains('pp_shop_apilo_settings'))
->willReturn($stmt);
$this->mockDb->method('select')
->with('pp_shop_apilo_settings', ['name', 'value'])
->willReturn([]);
$this->assertIsArray($this->repository->getSettings('apilo'));
}
public function testShopproProviderWorks(): void
{
$stmt = $this->createMock(\PDOStatement::class);
$stmt->method('fetchAll')->willReturn([
['name' => 'domain', 'value' => 'test.com'],
]);
$this->mockDb->method('query')
->with($this->stringContains('pp_shop_shoppro_settings'))
->willReturn($stmt);
$this->mockDb->method('select')
->with('pp_shop_shoppro_settings', ['name', 'value'])
->willReturn([
['name' => 'domain', 'value' => 'test.com'],
]);
$settings = $this->repository->getSettings('shoppro');
$this->assertSame('test.com', $settings['domain']);

BIN
updates/0.30/ver_0.333.zip Normal file

Binary file not shown.

View File

@@ -0,0 +1,26 @@
{
"changelog": "Ochrona przed podwójnym składaniem zamówienia (order submit token)",
"version": "0.333",
"files": {
"added": [
"api-docs/api-reference.json",
"api-docs/index.html"
],
"deleted": [
],
"modified": [
"autoload/front/Controllers/ShopBasketController.php",
"templates/shop-basket/address-form.php",
"templates/shop-basket/summary-view.php"
]
},
"checksum_zip": "sha256:1295fb94d7870c555e0108f5a925f6f995f46a26916e64bd63dee1b7db223457",
"sql": [
],
"date": "2026-03-10",
"directories_deleted": [
]
}

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,5 @@
<?
$current_ver = 332;
$current_ver = 333;
for ($i = 1; $i <= $current_ver; $i++)
{