diff --git a/.paul/PROJECT.md b/.paul/PROJECT.md new file mode 100644 index 0000000..5d8fbf4 --- /dev/null +++ b/.paul/PROJECT.md @@ -0,0 +1,69 @@ +# centrumcopy.com.pl + +## What This Is + +Strona internetowa dla małej firmy, prezentująca ofertę produktów i dane kontaktowe. Serwis informacyjny dla firmy sprzedającej drukarki, zbudowany w oparciu o framework Kohana (PHP). + +## Core Value + +Klienci mogą poznać ofertę drukarek firmy i skontaktować się z nią. + +## Current State + +| Attribute | Value | +|-----------|-------| +| Version | 0.1.0 | +| Status | Prototype | +| Last Updated | 2026-04-30 | + +## Requirements + +### Validated (Shipped) + +- (none yet) + +### Active (In Progress) + +- [ ] [To be defined during planning] + +### Planned (Next) + +- [ ] [To be defined during planning] + +### Out of Scope + +- [To be identified during planning] + +## Target Users + +**Primary:** Potencjalni klienci szukający drukarek +- Osoby i firmy poszukujące drukarek i materiałów eksploatacyjnych +- Potrzebują szybkiego dostępu do oferty i danych kontaktowych + +## Context + +**Business Context:** +Mała firma sprzedająca drukarki, potrzebuje profesjonalnej strony internetowej do prezentacji oferty. + +**Technical Context:** +PHP z frameworkiem Kohana, struktura MVC, brak systemu zarządzania pakietami (composer). + +## Constraints + +### Technical Constraints +- PHP / Kohana framework +- Hosting z obsługą PHP +- Brak composer.json — ręczne zarządzanie zależnościami + +### Business Constraints +- Strona informacyjna (nie e-commerce) + +## Success Criteria + +- Klienci mogą poznać pełną ofertę drukarek firmy +- Klienci mogą skontaktować się z firmą przez stronę +- Strona działa poprawnie i jest responsywna + +--- +*PROJECT.md — Updated when requirements or context change* +*Last updated: 2026-04-30* diff --git a/.paul/ROADMAP.md b/.paul/ROADMAP.md new file mode 100644 index 0000000..5955351 --- /dev/null +++ b/.paul/ROADMAP.md @@ -0,0 +1,25 @@ +# Roadmap: centrumcopy.com.pl + +## Overview + +Budowa i ulepszanie strony informacyjnej firmy sprzedającej drukarki — od audytu istniejącego kodu, przez ulepszenia funkcjonalne, po wdrożenie produkcyjne. + +## Current Milestone + +**v0.1 Initial Release** (v0.1.0) +Status: Not started +Phases: 0 of TBD complete + +## Phases + +| Phase | Name | Plans | Status | Completed | +|-------|------|-------|--------|-----------| +| 1 | TBD | TBD | Not started | - | + +## Phase Details + +Phases will be defined during `/paul:plan`. + +--- +*Roadmap created: 2026-04-30* +*Last updated: 2026-04-30* diff --git a/.paul/STATE.md b/.paul/STATE.md new file mode 100644 index 0000000..f20f205 --- /dev/null +++ b/.paul/STATE.md @@ -0,0 +1,48 @@ +# Project State + +## Project Reference + +See: .paul/PROJECT.md (updated 2026-04-30) + +**Core value:** Klienci mogą poznać ofertę drukarek firmy i skontaktować się z nią. +**Current focus:** Project initialized — ready for planning + +## Current Position + +Milestone: v0.1 Initial Release +Phase: Not yet defined +Plan: None yet +Status: Ready to create roadmap and first PLAN +Last activity: 2026-04-30 — Project initialized + +Progress: +- Milestone: [░░░░░░░░░░] 0% + +## Loop Position + +Current loop state: +``` +PLAN ──▶ APPLY ──▶ UNIFY + ○ ○ ○ [Ready for first PLAN] +``` + +## Accumulated Context + +### Decisions +None yet. + +### Deferred Issues +None yet. + +### Blockers/Concerns +None yet. + +## Session Continuity + +Last session: 2026-04-30 +Stopped at: Project initialization complete +Next action: Run /paul:plan to define phases and first plan +Resume file: .paul/PROJECT.md + +--- +*STATE.md — Updated after every significant action* diff --git a/.paul/codebase/architecture.md b/.paul/codebase/architecture.md new file mode 100644 index 0000000..5168825 --- /dev/null +++ b/.paul/codebase/architecture.md @@ -0,0 +1,351 @@ +# Architecture & Structure + +**Analysis Date:** 2026-04-30 + +--- + +## Directory Layout + +``` +centrumcopy.com.pl/ # Docroot / front controller +├── index.php # Front controller (entry point) +├── robots.txt +├── application/ # Application code (APPPATH) +│ ├── cache/ # Kohana internal cache (file-based) +│ ├── config/ # All configuration files +│ ├── controllers/ # MVC Controllers +│ │ ├── base_admin.php # Abstract base for admin controllers +│ │ ├── base_front.php # Abstract base for front controllers +│ │ ├── install.php # Installation controller +│ │ ├── admin/ # Admin panel controllers +│ │ └── front/ # Public-facing controllers +│ ├── helpers/ # (empty — helpers live in libraries/drivers) +│ ├── i18n/pl_PL/ # Polish locale strings +│ ├── libraries/ # Extended/custom libraries +│ │ └── drivers/ # Driver extensions +│ ├── logs/ # Error/application logs +│ ├── models/ # ORM models +│ └── views/ # PHP view templates +│ ├── admin/ # Admin panel partial views +│ ├── front/ # Public partial views +│ ├── gmaps/ # Google Maps JS view +│ ├── pagination/ # Pagination style templates +│ ├── admin_layout.php # Admin full-page layout +│ ├── admin_login.php # Admin login page +│ └── default_layout.php # Public full-page layout +├── modules/ # Kohana modules (MODPATH) +│ ├── gmaps/ # Google Maps integration module +│ └── debug_toolbar/ # Debug toolbar module +├── system/ # Kohana framework core (SYSPATH) +│ └── core/ # Bootstrap, Event, Kohana, Benchmark +├── css/ # Public stylesheets +├── js/ # Public JavaScript (jQuery, TinyMCE, etc.) +├── images/ # Public images +├── flash/ # Flash banner assets +├── uploads/ # User-uploaded files +└── stara/ # Legacy static HTML site (archived) +``` + +--- + +## MVC Structure + +### Controllers + +**Location:** `application/controllers/` + +Controllers use Kohana 2.x naming: `{Name}_Controller` extends a base class. File name is lowercase, class name is `PascalCase_Controller`. + +**Base classes (abstract):** + +| File | Class | Extends | Role | +|------|-------|---------|------| +| `application/controllers/base_front.php` | `Base_Front_Controller` | `Controller` | Sets up front layout (`default_layout`), session, menu, SEO metadata | +| `application/controllers/base_admin.php` | `Base_Admin_Controller` | `Controller` | Sets up admin layout (`admin_layout`), enforces auth guard, manages flash messages | + +**Front (public) controllers** — `application/controllers/front/`: + +| File | Class | Handles | +|------|-------|---------| +| `front/page.php` | `Page_Controller` | Static CMS pages, homepage redirect, contact page with Google Maps | +| `front/welcome.php` | `Welcome_Controller` | (unused/fallback) | + +**Admin controllers** — `application/controllers/admin/`: + +| File | Class | Handles | +|------|-------|---------| +| `admin/page.php` | `Page_Controller` | Edit CMS page content via TinyMCE | +| `admin/user.php` | `User_Controller` | Login, logout, password change | +| `admin/welcome.php` | `Welcome_Controller` | Admin dashboard index | + +Note: Both `front/page.php` and `admin/page.php` define `Page_Controller` — they are isolated by directory scoping during routing. + +**Auth guard pattern in `Base_Admin_Controller`:** +```php +if (!$this->session->get('admin') && Router::$method != 'login' && Router::$method != 'logout') { + url::redirect('admin/login'); +} +``` + +**`__call` magic method** is used in `Page_Controller` (front) to route any unknown URL segment to `show($name)`, enabling slug-based page lookup. + +### Models + +**Location:** `application/models/` + +All models extend `ORM` (Kohana's ActiveRecord-style ORM). Model file name is lowercase; class name is `{Name}_Model`. + +| File | Class | Table | Notes | +|------|-------|-------|-------| +| `models/page.php` | `Page_Model` | `page` | Singular table name; supports lookup by `name` slug | +| `models/user.php` | `User_Model` | `user` | Primary val = `username`; SHA1+salt password hashing | +| `models/news.php` | `News_Model` | `news` | Singular; sorted by `created_at DESC` | +| `models/gallery.php` | `Gallery_Model` | `gallery` | Has many `gallery_images`; sorted `created_at ASC` | +| `models/gallery_image.php` | `Gallery_Image_Model` | `gallery_image` | Belongs to `gallery`; sorted by `id ASC` | + +**ORM lookup pattern:** +```php +ORM::factory('page')->where('name', $slug)->find(); +if (!$page->loaded) { return $this->error404(); } +``` + +### Views + +**Location:** `application/views/` + +Views are plain PHP templates. Layout views are full HTML documents; partial views are HTML fragments assigned to `$content`. + +**Layout views (full pages):** + +| File | Used by | +|------|---------| +| `views/default_layout.php` | All front controllers via `Base_Front_Controller` | +| `views/admin_layout.php` | All admin controllers via `Base_Admin_Controller` | +| `views/admin_login.php` | `User_Controller::login()` | + +**Partial views — front:** `views/front/` + +| File | Rendered by | +|------|-------------| +| `front/page_show.php` | `Page_Controller::show()` | +| `front/page_contact.php` | `Page_Controller::contact()` | +| `front/error404.php` | `Base_Front_Controller::error404()` | + +**Partial views — admin:** `views/admin/` + +| File | Rendered by | +|------|-------------| +| `admin/page_edit.php` | `admin/Page_Controller::edit()` | +| `admin/password.php` | `User_Controller::password()` | +| `admin/welcome.php` | `admin/Welcome_Controller::index()` | +| `admin/error404.php` | `Base_Admin_Controller::error404()` | + +**View rendering pattern:** +```php +$page_view = new View('front/page_show'); +$page_view->page = $page; // assign data to partial +$this->view->content = $page_view; // embed partial in layout +$this->view->render(true); // output full layout +``` + +--- + +## Routing + +**Config file:** `application/config/routes.php` + +Kohana 2.x routing maps URL patterns (regex) to `directory/controller/method` targets. Routes are evaluated top-to-bottom; first match wins. + +```php +$config['_default'] = 'front/page/homepage'; // / → Front\Page::homepage() + +// Admin routes +$config['admin'] = 'admin/welcome/'; // /admin +$config['admin/login'] = 'admin/user/login'; // /admin/login +$config['admin/logout'] = 'admin/user/logout'; // /admin/logout +$config['admin/password'] = 'admin/user/password'; // /admin/password +$config['admin/page/(.*)'] = 'admin/page/edit/$1'; // /admin/page/{slug} +$config['admin/(.*)'] = 'admin/$1'; // /admin/... + +// Front routes +$config['kontakt'] = 'front/page/contact'; // /kontakt +$config['galeria/?(.*)'] = 'front/gallery/$1'; // /galeria/... +$config['aktualnosci/?(.*)'] = 'front/news/$1'; // /aktualnosci/... +$config['(.+)'] = 'front/page/$1'; // /{any-slug} → Page::show() +``` + +**Slug routing:** The catch-all `(.+)` route passes the URL slug to `front/page/`. `Page_Controller::show($name)` then queries the database for a page with `name = $slug`. This means all CMS pages live in a flat namespace matched against the `page.name` column. + +**URL rewriting:** `index_page` is commented out in `application/config/config.php`, meaning clean URLs (no `index.php` in path) require Apache `mod_rewrite` or equivalent. + +--- + +## Module System + +**Module path:** `modules/` (MODPATH) + +Modules are configured in `application/config/config.php` under `$config['modules']`. Kohana merges module paths into the file search cascade (controllers, views, libraries, etc. from a module are auto-discoverable). + +**Active modules:** + +| Module | Path | Purpose | +|--------|------|---------| +| `gmaps` | `modules/gmaps/` | Google Maps v2 API wrapper — `Gmap` library, marker helpers, JS view | + +**Available but disabled modules** (commented out in config): +- `auth`, `forge`, `kodoc`, `media`, `archive`, `payment`, `unit_test`, `object_db` + +**`debug_toolbar` module** exists at `modules/debug_toolbar/` but is **not loaded** in config. + +**Module internal structure** (gmaps example): +``` +modules/gmaps/ +├── config/ # Module config +├── controllers/ # Module controllers (if any) +├── i18n/ +├── libraries/ # Gmap, Gmap_Marker libraries +├── models/ +└── views/ # gmaps/javascript.php +``` + +**Custom application-level extensions** (not modules — override framework classes): + +| File | Purpose | +|------|---------| +| `application/libraries/MY_Database.php` | Extends `Database_Core` — fixes `COUNT()` column escaping with table prefix | +| `application/libraries/MY_Gmap_Marker.php` | Extends Gmap marker from the gmaps module | +| `application/libraries/drivers/Database.php` | Custom database driver wrapper | +| `application/libraries/drivers/MY_form.php` | Extended form helper | +| `application/libraries/drivers/MY_html.php` | Extended html helper (adds `span_class()`, etc.) | +| `application/libraries/drivers/MY_valid.php` | Extended validation rules | +| `application/libraries/drivers/categories.php` | Category tree helper | +| `application/libraries/drivers/javascript.php` | JavaScript generation helper | + +--- + +## Business Domains + +This is a **B2B product catalogue + CMS** for a photocopier/office equipment distributor (Centrum Copy Rzeszów). + +### CMS / Static Pages +- **Primary domain.** All content pages are rows in the `page` table, looked up by a URL `name` slug. +- Pages have: `title`, `header`, `content` (HTML via TinyMCE), `meta_description`, `meta_keywords`. +- Admin edits pages via WYSIWYG at `/admin/page/{slug}`. +- Menu structure is **hardcoded** in `application/config/application.php` under `$config['menu_nav']` — changing the menu requires a code deploy. +- Content domains visible in admin menu: O firmie, Powielacze cyfrowe RISO, Pełnokolorowe urządzenia Inkjet RISO ComColor, Urządzenia biurowe (kolorowe/monochromatyczne A4/A3), Plotery i skanery, Finansowanie, Serwis, Usługi, Kontakt, Szybki kontakt. + +### Gallery +- Model: `Gallery_Model` (has_many `Gallery_Image_Model`) +- Route: `/galeria/...` → `front/gallery` controller +- Note: `application/controllers/front/gallery.php` does not exist as a file — gallery controller is **missing or not committed**. + +### News / Aktualności +- Model: `News_Model` +- Route: `/aktualnosci/...` → `front/news` controller +- Note: `application/controllers/front/news.php` does not exist — news controller is **missing or not committed**. + +### Contact Page +- Route `/kontakt` → `Page_Controller::contact()` +- Renders Google Maps v2 marker at configured lat/lon (`application/config/application.php` → `$config['gmaps']`). +- Google Maps centre: `50.0491231, 21.9869502` (Rzeszów, ul. Okulickiego 9). + +### Admin Panel +- Session-based authentication. Credentials: SHA1(salt + password) stored in `user` table. +- Single-user admin — no roles enforced beyond session presence. +- Admin navigates to hardcoded page slugs from the sidebar in `admin_layout.php`. +- Features: edit page content, change admin password, logout. + +--- + +## Request Lifecycle + +``` +Browser Request + | + v +index.php (front controller) + - defines DOCROOT, APPPATH, MODPATH, SYSPATH + - sets IN_PRODUCTION = false + - requires system/core/Bootstrap.php + | + v +system/core/Bootstrap.php + - loads Benchmark, utf8, Event, Kohana + - Kohana::setup() (loads config, modules, sets error handlers) + | + v +Event::run('system.ready') (hooks, if enabled — currently disabled) + | + v +Event::run('system.routing') + - Router matches URI against application/config/routes.php + - Determines: directory, controller, method, arguments + | + v +Event::run('system.execute') + - Instantiates controller: new {Name}_Controller() + - __construct() runs: + - parent::__construct() (Kohana base Controller) + - Base_Front/Admin_Controller::__construct() + - Creates View object for layout + - Starts Session + - Loads config (title, meta, menu_nav, etc.) + - [Admin only] Auth guard → redirect to login if not authed + - Calls controller method (e.g., show(), edit(), login()) + - Method queries ORM models + - Creates partial View, assigns data + - Assigns partial to $this->view->content + - $this->view->render(true) → outputs full HTML + | + v +Event::run('system.shutdown') (cleanup) + | + v +Response sent to browser +``` + +**Session:** Native PHP sessions, 30-minute expiration, validated by `user_agent`. Session name: `Frisson_session`. + +**Database:** MySQLi driver, single `default` connection, no table prefix, UTF-8 charset, query benchmarking enabled. + +**Output compression:** gzip enabled (`$config['output_compression'] = TRUE`). + +**Error handling:** Errors logged to `application/logs/` at threshold 1 (errors + exceptions). `display_errors` is off in production. + +--- + +## Configuration Files + +| File | Purpose | +|------|---------| +| `application/config/application.php` | Site title, email, Google Maps coords, navigation menu, Google Analytics | +| `application/config/config.php` | Kohana core settings: domain, modules list, cache, compression, hooks | +| `application/config/database.php` | MySQLi connection credentials | +| `application/config/routes.php` | URL routing rules | +| `application/config/session.php` | Session driver, name, expiration | +| `application/config/pagination.php` | Pagination defaults (5 items/page, segment 3) | +| `application/config/email.php` | Email settings | +| `application/config/cookie.php` | Cookie settings | +| `application/config/tiny_mce.php` | TinyMCE upload paths for admin editor | +| `application/config/upload.php` | File upload settings | +| `application/config/locale.php` | Locale/timezone | +| `application/config/gmaps.php` | Google Maps module config | +| `application/config/debug_toolbar.php` | Debug toolbar settings | + +--- + +## Key Observations & Gaps + +1. **Missing controllers:** `application/controllers/front/gallery.php` and `application/controllers/front/news.php` are referenced in routes but absent. Routes for `/galeria/` and `/aktualnosci/` will 404. + +2. **Hardcoded navigation:** `$config['menu_nav']` in `application/config/application.php` defines the entire site menu statically. Adding/removing menu items requires editing this config file and redeploying. + +3. **Admin menu also hardcoded:** `application/views/admin_layout.php` contains inline HTML listing every editable page slug. Must be manually updated to match `page` table contents. + +4. **IN_PRODUCTION = false:** Set in `index.php`. Must be changed to `true` before deploying to live server to enable Google Analytics and suppress demo controllers. + +5. **Kohana version:** 2.3.4 (codename "buteo regalis") — very old, unmaintained framework. No Composer, no autoloading beyond Kohana's own file cascade. + +6. **Auth security:** `User_Controller::login()` contains `print_r($_POST)` debug statement (line 29). This leaks credentials in the HTTP response. Remove before any production use. + +7. **No test runner configured.** No test files detected. diff --git a/.paul/codebase/concerns.md b/.paul/codebase/concerns.md new file mode 100644 index 0000000..f370b53 --- /dev/null +++ b/.paul/codebase/concerns.md @@ -0,0 +1,274 @@ +# Concerns & Technical Debt + +**Analysis Date:** 2026-04-30 + +--- + +## Security Issues + +### [HIGH] Database credentials committed to version control +- **File:** `application/config/database.php` +- **Detail:** Production MySQL username (`host420804_db`) and plaintext password (`VanMzwjUn85ySRyR`) are hardcoded and committed to git. +- **Impact:** Anyone with access to the repository has full database access. This is especially dangerous given the repo is on a shared hosting environment. +- **Fix:** Move credentials to a `.env` file or server-level environment variables. Add `application/config/database.php` to `.gitignore` and use a `database.php.example` as template. + +### [HIGH] FTP credentials committed to version control +- **File:** `.vscode/ftp-kr.json` +- **Detail:** Production FTP credentials are committed — host `host420804.hostido.net.pl`, username `www@centrumcopy.com.pl`, and plaintext password (`JHycfrHnyEAYsJHtR26C`). Protocol is plain FTP (not SFTP). +- **Impact:** Full read/write access to the production server's `public_html` for anyone with repo access. +- **Fix:** Add `.vscode/ftp-kr.json` to `.gitignore`. Switch from FTP to SFTP. Store credentials outside the repository. + +### [HIGH] Unprotected install controller accessible in production +- **File:** `application/controllers/install.php` +- **Detail:** The `install` route is publicly routable (`$config['install/*(.*)'] = 'install/$1'` in `application/config/routes.php`). The controller can create users and insert database records. No authentication check. Visiting `/install/init` in a browser would recreate seed data, including writing admin users. +- **Impact:** Any visitor can trigger `/install/user/admin` which resets admin credentials to `admin/admin`. +- **Fix:** Delete or disable the install controller in production. At minimum wrap every method with an IP whitelist or a production check using `IN_PRODUCTION`. + +### [HIGH] Force-login backdoor controller +- **File:** `application/controllers/admin/force.php` +- **Detail:** `Force_Controller::login()` logs in as user ID 1 with no password check whatsoever, then sets the admin session. It is reachable at `/admin/force/login` via the catch-all route `$config['admin/(.*)'] = 'admin/$1'`. +- **Impact:** Any visitor can visit `/admin/force/login` and immediately gain full admin access without credentials. +- **Fix:** Delete this file immediately. It appears to be a developer debug shortcut left in the codebase. + +### [HIGH] Debug output (`print_r($_POST)`) in the login controller +- **File:** `application/controllers/admin/user.php`, line 29 +- **Detail:** `print_r($_POST)` is called on every POST to the login form. This outputs all submitted POST data (including username and password) directly to the browser response. +- **Impact:** Credentials are exposed in the HTTP response body. May also interfere with redirects. +- **Fix:** Remove this line immediately. + +### [HIGH] Unescaped HTML output of page content in front-end views +- **Files:** `application/views/front/page_show.php` (line 5), `application/views/front/page_contact.php` (line 5), `application/views/default_layout.php` (lines 73, 75) +- **Detail:** `$page->content`, `$page->header`, `$szybki_kontakt->content`, and `$szybki_kontakt->header` are echoed raw with no escaping. Admin-saved HTML content is intentional (TinyMCE WYSIWYG), but if the admin account is compromised, an attacker could inject arbitrary JavaScript. +- **Impact:** Stored XSS is possible through the admin panel if admin credentials are stolen. +- **Fix:** Accept risk intentionally for trusted admin HTML content, but enforce strong auth (see CSRF and password hashing concerns). Document this explicitly. + +### [HIGH] No CSRF protection on any form +- **Files:** All forms — `admin_login.php`, `admin/page_edit.php`, `admin/password.php` +- **Detail:** Zero CSRF tokens are generated or validated on any POST form. Kohana 2.x includes no built-in CSRF protection. The forms rely solely on JavaScript-side validation, which is easily bypassed. +- **Impact:** Any site can submit a form on behalf of a logged-in admin, changing page content or admin credentials. +- **Fix:** Generate a per-session CSRF token in the base controllers and validate it on every POST. + +### [HIGH] Weak password hashing (SHA-1 with weak salt) +- **Files:** `application/controllers/admin/user.php` (lines 33, 93, 97), `application/controllers/install.php` (lines 29, 36, 87, 93) +- **Detail:** Passwords are hashed using `sha1($salt . $password)`. The salt is generated as `md5(rand(100000,999999) . $username . $email)` — a low-entropy 6-digit random number seeded with predictable data. SHA-1 is cryptographically broken for password storage. +- **Impact:** If the database is breached, passwords are easily crackable via rainbow tables or brute force. +- **Fix:** Migrate to `password_hash()` / `password_verify()` with `PASSWORD_BCRYPT` or `PASSWORD_ARGON2ID`. + +### [MEDIUM] No rate limiting or lockout on the login endpoint +- **File:** `application/controllers/admin/user.php` +- **Detail:** The login form has no brute-force protection. There is no account lockout, CAPTCHA, or IP-based rate limiting after repeated failures. The `last_failed` timestamp is recorded but never acted upon. +- **Impact:** Automated brute-force attacks against the admin login are unimpeded. +- **Fix:** Add lockout logic after N failures within a time window, or integrate a CAPTCHA (Kohana has a Captcha library available). + +### [MEDIUM] Session ID never regenerated after login +- **File:** `application/config/session.php` (line 43: `'regenerate' => 0`), `application/controllers/admin/user.php` +- **Detail:** `session.regenerate` is set to `0` (disabled). No manual session ID regeneration occurs on successful login. This allows session fixation attacks. +- **Fix:** Call `session_regenerate_id(true)` immediately after successful login, or set `'regenerate' => 1`. + +### [MEDIUM] Cookies are not HttpOnly +- **File:** `application/config/cookie.php` (line 28: `'httponly' => FALSE`) +- **Detail:** Session cookies are accessible via JavaScript. Combined with any XSS vector, this enables session hijacking. +- **Fix:** Set `'httponly' => TRUE`. + +### [MEDIUM] Cookies are not Secure (no HTTPS enforcement) +- **File:** `application/config/cookie.php` (line 23: `'secure' => FALSE`), `.htaccess` +- **Detail:** No HTTPS redirect is configured in `.htaccess`. Cookies are sent over plain HTTP. Google Maps API is loaded over HTTP (`http://maps.google.com/...`). +- **Fix:** Add HTTPS redirect to `.htaccess`. Set cookie `'secure' => TRUE`. Use `https://` for external resources. + +### [MEDIUM] Google Maps v2 API key committed to repository +- **File:** `application/config/gmaps.php` +- **Detail:** A Google Maps API v2 key is hardcoded and committed. Google Maps v2 has been deprecated and shut down for years. +- **Fix:** Remove the key. Migrate to Google Maps v3 (which uses domain restriction, not a key in the same way), or use an alternative mapping service. + +### [LOW] `IN_PRODUCTION` flag is `false` in the committed index.php +- **File:** `index.php` (line 16: `define('IN_PRODUCTION', false)`) +- **Detail:** The production flag is hardcoded as `false`. This means Google Analytics is never included on the live site (guarded by `IN_PRODUCTION`). It also suggests dev and production use the same code file with no environment separation. +- **Fix:** Use an environment variable or server-detected value to set this flag per environment. + +--- + +## Technical Debt + +### [HIGH] `filter_var()` emulation with security bypass +- **File:** `index.php` (lines 68–80) +- **Detail:** If the PHP `filter` extension is not installed, `filter_var()` is replaced with a stub that always returns `true`, meaning all IP/URL validation silently passes without actually validating anything. +- **Impact:** If running on a server without the filter extension, all input validation using `filter_var` is bypassed. +- **Fix:** Require the `filter` extension explicitly in server requirements. Remove the stub. + +### [HIGH] Deprecated `mysql_*` functions used in system database driver +- **File:** `system/libraries/drivers/Database/Mysql.php` +- **Detail:** The `Mysql` driver uses `mysql_connect()`, `mysql_query()`, `mysql_close()`, etc. These functions were removed in PHP 7.0. The application is configured to use the `mysqli` driver (`application/config/database.php`), but the old `Mysql.php` driver still exists and would fail completely if the config were changed. +- **Impact:** The old driver is dead code but signals the PHP version constraint this codebase was designed for. +- **Fix:** Confirm `mysqli` driver is always used. Delete `system/libraries/drivers/Database/Mysql.php` or mark it clearly as unsupported. + +### [HIGH] Commented-out dead code throughout controllers +- **Files:** `application/controllers/admin/user.php` (lines 8–10, 29–30, 46, 63), `application/controllers/base_admin.php` (lines 13, 31, 40–41), `application/controllers/base_front.php` (lines 12–17, 40–43) +- **Detail:** Large blocks of commented-out functionality exist: disabled profiler, disabled cookie-based redirect, disabled homepage layout, disabled `__destruct` rendering. These represent abandoned design decisions. +- **Fix:** Remove commented-out code. Use git history if rollback is ever needed. + +### [MEDIUM] `stara/` directory — entire old website committed to repository +- **File:** `stara/` directory +- **Detail:** An old version of the website (`index.htm`, Flash files, old HTM pages, images) is committed to the repository root and likely deployed to production alongside the current application. +- **Impact:** Old pages may be publicly accessible. Increases repository size. Potential security exposure if old files have vulnerabilities. +- **Fix:** Remove `stara/` from the repository. If archival is needed, move it to a separate repository or offline storage. + +### [MEDIUM] Google Maps v2 integration (defunct API) +- **Files:** `application/config/gmaps.php`, `application/controllers/front/page.php`, `modules/gmaps/` +- **Detail:** The entire `gmaps` module integrates Google Maps JavaScript API v2, which was shut down in 2013. The map on the contact page will not render. +- **Fix:** Rewrite the contact page map using Google Maps v3 or an alternative (e.g., Leaflet with OpenStreetMap). Remove the `gmaps` module. + +### [MEDIUM] Adobe Flash integration +- **Files:** `flash/centrumcopy.swf`, `flash/expressInstall.swf`, `application/views/default_layout.php` (lines 44–46, 94–102) +- **Detail:** Adobe Flash Player support was dropped by all browsers at end of 2020. The Flash banner on the homepage cannot be displayed. +- **Fix:** Remove the Flash files and `swfobject` integration from the layout. Replace with a static image or CSS/HTML5 animation. + +### [MEDIUM] Menu and navigation structure hardcoded in two separate places +- **Files:** `application/config/application.php` (`$config['menu_nav']`), `application/views/admin_layout.php` (admin sidebar links) +- **Detail:** The navigation menu is defined once in config (rendered for front-end) and a parallel, nearly duplicate list exists hardcoded in the admin layout view. Adding a new page requires editing both files. +- **Fix:** Drive the admin sidebar from the same data source as the front-end menu config. + +### [LOW] TinyMCE 3.x (ancient WYSIWYG editor) +- **File:** `js/tiny_mce/` +- **Detail:** TinyMCE 3.x is bundled. TinyMCE is now at version 7. Version 3 is no longer maintained and may have known XSS vulnerabilities in the editor itself. +- **Fix:** Upgrade to TinyMCE 6/7 or replace with a modern editor (e.g., Quill, ProseMirror). + +### [LOW] jQuery and jQuery UI versions are unversioned/unknown +- **Files:** `js/jquery.min.js`, `js/jquery-ui.min.js` +- **Detail:** No version number is visible in the filenames. Given the use of IE7 polyfills and Flash, these are likely very old versions. +- **Fix:** Replace with a pinned, modern version (jQuery 3.x). Consider migrating away from jQuery UI entirely. + +### [LOW] IE7 polyfill scripts loaded from external CDN via HTTP +- **Files:** `application/views/default_layout.php` (line 15), `application/views/admin_layout.php` (line 10), `application/views/admin_login.php` (line 10) +- **Detail:** `ie7-js.googlecode.com` is loaded as an external HTTP script. Google Code shut down in 2016; this URL returns a 404 or is hijacked. IE7 support is irrelevant in 2024+. +- **Fix:** Remove all IE7 conditional comments and scripts. + +--- + +## Performance Concerns + +### [MEDIUM] N+1 query risk on every page load — `szybki-kontakt` page +- **File:** `application/controllers/base_front.php` (line 31) +- **Detail:** Every page load on the front-end executes `ORM::factory('page')->where('name', 'szybki-kontakt')->find()` in the base controller constructor. This is a database query run on every single front-end request, even pages that don't display the sidebar contact snippet. +- **Fix:** Cache this result in a static variable or application-level cache. Consider storing it in config if the content rarely changes. + +### [MEDIUM] Database query benchmarking enabled in production config +- **File:** `application/config/database.php` (line 28: `'benchmark' => TRUE`) +- **Detail:** Query benchmarking adds overhead to every database call. +- **Fix:** Set `'benchmark' => FALSE` in production, or use the `IN_PRODUCTION` flag to switch configs. + +### [LOW] No HTTP caching headers configured +- **Files:** `.htaccess`, `application/config/` +- **Detail:** No `Cache-Control`, `Expires`, or ETags are configured for static assets (CSS, JS, images). The `.htaccess` has no asset caching rules. +- **Fix:** Add browser caching rules in `.htaccess` for static file extensions. + +### [LOW] All front-end JavaScript loaded synchronously in `` +- **File:** `application/views/default_layout.php` (lines 18–30) +- **Detail:** 7+ JS files are loaded with blocking `