مطلوب
` +- **No form libraries** — all hand-rolled + +### Responsive Breakpoints + +| Breakpoint | Layout | +|------------|--------| +| Default (mobile) | Single column, BottomNav, hamburger menu | +| `md:` (768px) | Desktop nav, 2-3 column grids | +| `lg:` (1024px) | PropertyDetail sidebar, 3-column grids | + +--- + +## 7. Owner Pages Analysis (Dashboard Section) + +| Route | File | Lines | Status | Data Source | +|-------|------|-------|--------|-------------| +| `/owner/properties` | `owner/properties/page.js` | 2057 | ✅ Active | API (`getMyRentListings`, `getMySaleListings`) + localStorage cache | +| `/owner/properties/add` | `owner/properties/add/page.js` | 700+ | ✅ Active | API (`addRentProperty`, `addSaleProperty`, `uploadPicture`) | +| `/owner/reservations` | `owner/reservations/page.js` | 1400+ | ❌ Commented out | Mock data (commented) | +| `/owner/bookings` | `owner/bookings/page.js` | 560+ | ⚠️ Demo | localStorage mock data only | +| `/owner/calendar` | `owner/calendar/page.js` | 580+ | ⚠️ Demo | localStorage mock data only | +| `/owner/profits` | `owner/profits/page.js` | 600+ | ⚠️ Demo | localStorage mock data only | +| `/owner/account-book` | `owner/account-book/page.js` | 500+ | ✅ Active | API (`getOwnerStatistics`) | + +--- + +## 8. Admin Functionality + +| Component | Status | Data Source | +|-----------|--------|-------------| +| BookingRequests | ✅ Active | Real API (`getReservations`, `adminConfirmDeposit`) | +| Users | ❌ Not implemented | — | +| Properties | ❌ Not implemented | — | +| LedgerBook | ⚠️ Mock only | 3 hardcoded mock transactions | +| Dashboard | ❌ Not implemented | — | + +Designed for internal admin use at `/admin` — tabs for Bookings/Users/Properties/Ledger/Dashboard. + +--- + +## 9. Known Technical Debt + +### Dead Code + +| File | Dead Lines | Issue | +|------|-----------|-------| +| `api.js` | Lines 1-370 (370 lines) | Entire legacy version commented out | +| `StarRating.js` | Lines 1-93 (93 lines) | Old framer-motion version commented out | +| `PropertyRatingList.js` | ~150 lines | Old version commented out | +| `PropertyRatingForm.js` | ~220 lines | Old version commented out | +| `contexts/PropertyContext.js` | Entire file | Never mounted | +| `utils/PropertyContext.js` | Entire file | Duplicate orphan | + +### Code Duplication + +| Pattern | Files | Description | +|---------|-------|-------------| +| Leaflet maps | 3 separate files | `PropertyMapWithMarkers.js`, `home/PropertyMap.js`, `property/PropertyMap.js` — all setup Leaflet identically | +| Rating forms | `PropertyRatingForm.js` (317) + `CustomerRatingForm.js` (92) | ~75% code overlap; both define identical `RatingField` inline | +| formatCurrency | 4+ locations | Scattered across files with slightly different logic | +| Image URL building | 4+ locations | Different implementations for same task | +| Notifications page | `/notifications/page.js` vs `NotificationsContext` | Page duplicates all context state/logic | + +### Architecture Issues + +| Issue | Impact | +|-------|--------| +| No middleware.js | All route protection is client-side only | +| JWT in localStorage | XSS-vulnerable token storage | +| Client-side role checks | Users can modify JWT to elevate privileges | +| Owner pages use mock data | `/owner/bookings`, `/owner/calendar`, `/owner/profits` are demo-only | +| 3 unused UI libraries | DaisyUI, Flowbite, Yandex Maps imported but never used | +| No TypeScript | 112 JS files, no type safety | +| No ESLint | No linting configured | +| No testing framework | Zero tests | +| Flat route structure | No nested layouts; all pages share root layout | +| Active console.log | ~30+ files with console.log statements (security risk) | + +--- + +## 10. Dependencies + +### Production (18) + +| Package | Version | Purpose | +|---------|---------|---------| +| next | 16.1.6 | Framework | +| react / react-dom | ^18.3.1 | UI | +| firebase | ^12.11.0 | FCM push notifications | +| leaflet / react-leaflet | 1.9.4 / 4.2.1 | Maps | +| @pbe/react-yandex-maps | ^1.2.5 | Yandex Maps (unused) | +| framer-motion | ^12.29.2 | Animations | +| lucide-react | ^0.563.0 | Icons | +| flowbite / flowbite-react | 4.0.1 / 0.12.16 | UI library (unused) | +| react-hot-toast | ^2.6.0 | Toasts | +| i18next / react-i18next / i18next-browser-languagedetector | 25.8 / 16.5 / 8.2 | i18n | +| jspdf / html2canvas | 4.2.1 / 1.4.1 | PDF generation | +| xlsx | ^0.18.5 | Excel export | +| react-intersection-observer | ^10.0.3 | Scroll detection | + +### Dev (7) + +| Package | Version | Purpose | +|---------|---------|---------| +| tailwindcss | ^4.1.18 | CSS framework | +| @tailwindcss/postcss | ^4 | PostCSS plugin | +| postcss / autoprefixer | ^8.5.6 / ^10.4.23 | CSS processing | +| daisyui | ^5.5.14 | UI components (unused) | +| babel-plugin-react-compiler | 1.0.0 | React compiler optimization | + +### Missing (notable absences) +- No TypeScript +- No ESLint +- No testing (Jest, Playwright, Cypress) +- No state management library (Redux, Zustand) +- No data fetching library (React Query, SWR) +- No form library (React Hook Form, Formik) +- No security lib (helmet, cors, csurf) +- No HTTP client (axios, ky) +- No JWT lib (jsonwebtoken, jose) + +--- + +## 11. Security Summary + +*(See `security-audit-report.md` for full details)* + +| # | Finding | Severity | +|---|---------|----------| +| 1 | JWT in localStorage (XSS-theft) | 🔴 Critical | +| 2 | Stored XSS via Leaflet popup HTML | 🔴 Critical | +| 3 | OTP code logged to console | 🔴 Critical | +| 4 | No server-side middleware | 🔴 Critical | +| 5 | Passwords in URL query params | 🔴 Critical | +| 6 | IDOR on property edit/status APIs | 🔴 Critical | +| 7 | Client-only role checks | 🟠 High | +| 8 | HTTP endpoints leak tokens | 🟠 High | +| 9 | No CSP/security headers | 🟠 High | +| 10 | Mass assignment via spread | 🟠 High | +| 11 | Error messages leak internals | 🟠 High | +| 12 | Hardcoded IPs (10+ files) | 🟡 Medium | + +--- + +## 12. File Size Heatmap + +| Size Range | Files | Examples | +|------------|-------|----------| +| 1500-2100 lines | 2 | `PropertyDetail.js` (1743), `owner/properties/page.js` (2057) | +| 600-1200 lines | 6 | `api.js` (1198), `ClientLayout.js` (804), `login/page.js` (800+), `owner/properties/add/page.js` (700+), `app/page.js` (623), `owner/bookings/page.js` (560+) | +| 200-600 lines | 15 | Most page files | +| < 200 lines | ~70 | Enum files, smaller components, error/loading pages | diff --git a/security-audit-report.md b/security-audit-report.md new file mode 100644 index 0000000..e69f972 --- /dev/null +++ b/security-audit-report.md @@ -0,0 +1,488 @@ +# SweetHome — Full Security Audit & Pentest Report + +**Project:** SweetHome Next.js Real Estate Application +**Date:** June 16, 2026 +**Scope:** Client-side source code analysis (full white-box) + +--- + +## Executive Summary + +| Severity | Count | Key Issues | +|----------|-------|------------| +| 🔴 **CRITICAL** | 8 | JWT in localStorage, XSS via Leaflet, OTP in console, no middleware, passwords in URL params, IDOR on edit APIs | +| 🟠 **HIGH** | 12 | Client-only role checks, HTTP endpoints, credential logging, mass assignment, error leakage, no CSP | +| 🟡 **MEDIUM** | 15 | Hardcoded IPs, stale localStorage keys, weak validation, no security headers, FCM token exposure | +| 🟢 **LOW** | 6 | Missing maxLength, base64 avatar in storage, weak email regex | + +--- + +## 🔴 CRITICAL FINDINGS + +### C1. JWT Stored in `localStorage` (No httpOnly Cookie) + +**Files:** `app/services/AuthService.js:23-38`, `app/settings/page.js:335-339`, `app/payments/page.js:185-189` + +```javascript +const TOKEN_KEY = 'auth_token'; +const USER_KEY = 'cached_user'; + +const AuthService = Object.freeze({ + addToken(token) { + localStorage.setItem(TOKEN_KEY, token); // <-- XSS-accessible + }, + getToken() { + return localStorage.getItem(TOKEN_KEY); // <-- XSS-accessible + }, + deleteToken() { + localStorage.removeItem(TOKEN_KEY); + localStorage.removeItem(USER_KEY); + }, +``` + +**Impact:** Any XSS vulnerability gives attackers permanent token theft. No httpOnly, Secure, or SameSite protection. Token persists across tabs with no client-side expiration enforcement. + +**Multiple fallback keys** (fragmented storage): +- `auth_token` (primary) +- `token`, `accessToken`, `authToken` (fallbacks in settings, payments, reservations pages) +- `cached_user` (user profile data) +- `userProfile`, `userAvatar` (profile page - base64 images!) + +--- + +### C2. Stored XSS via Leaflet Popup HTML Construction + +**File:** `app/components/PropertyMapWithMarkers.js:51-65` + +```javascript +const popupContent = ` ++ ${property.address || property.location?.address || ''} +
+ ${property.images && property.images.length > 0 + ? `