Commit Graph
8 Commits
Author SHA1 Message Date
s.esmaeiliandClaude Opus 5 4efe543d62 parity(api,apps): security hotfix stage 2 - real customer sessions, close IDOR
Stage 1 narrowed GET /customers but did not close the leak: the response still
carried every customer id, and /customers/:id, /:id/orders and
/:id/ledger-entries were still public, so the full customer book was still two
requests away. The user caught this. Stage 2 deletes the id-bearing surface.

Customer JWT, separate from the admin one (T1):
  - new src/modules/customer-auth/ with its own passport strategy,
    CustomerJwtGuard, @CustomerAuth() and @CurrentCustomer()
  - signed with JWT_CUSTOMER_SECRET, and every token carries typ:'customer'
    which the strategy verifies; both checks are present deliberately
  - customer state re-read per request, so deactivating takes effect at once
  - mirrors the reference's own split: auth:api vs auth('api-customer')

Real OTP (D6), porting ApiMobileController::userAuth/userVerfiy (:39-64):
  - new CustomerOtp table, additive migration, nothing existing touched
  - parity behaviour: rand(1000,9999), active-customer filter, faTOen digit
    normalisation on both number and code, rejection on mismatch
  - approved improvements over the reference: bcrypt-hashed code, 2-minute
    expiry, 5 attempts then lockout, single use, send throttle (60s per
    number, 5/number and 20/IP per 10 min), and no number enumeration

Routes removed, replaced by token-derived equivalents:
  GET customers, customers/:id, /:id/orders, /:id/ledger-entries
    -> GET customer/me, customer/me/orders, customer/me/ledger-entries
No route accepts a customer id any more, so the IDOR is closed structurally
rather than by a check. The admin panel was unaffected (admin/customers-omde/*).

Both apps migrated in the same commit per the v1/v2 parity rule: token-based
session store, Bearer header, 401 -> clear session and route to login, real
two-step OTP login. Each app keeps its own markup and styling; only logic moved.

Tests: auth-smoke.sh extended with the stage-2 assertions, 46 passed 0 failed
against a live server. jest installed dev-only (user-approved) so pnpm test
works for the first time: 7 passed covering faToEn, which moved to its own
digits.ts to be testable without booting Nest. Typecheck clean on api,
user-app and user-app-v2; both apps build.

[ref: henza_server ApiMobileController.php:39-78]

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 01:20:00 +03:30
s.esmaeili ef1d4638cc admin user and ui panel 2026-09-21 08:32:31 +03:30
s.esmaeili b80fa9bcfb Redesign product detail page and fix icon/cart reactivity bugs
- SingleProduct.vue: rebuild gallery/header/action bar as a self-scrolling
  layout with a sticky photo, solid-on-scroll header matching PageBar, and
  a full-screen image preview (blurred overlay, centered thumbnail strip)
- Add GallerySlider.vue: pointer-based swipe carousel isolated in an
  LTR subtree, fixing RTL/transform sign mismatch that caused slide jumps
- Fix Icon.vue: icon was read into a plain ref once at setup and never
  updated on prop change; switch to computed so icon swaps (e.g. cart
  qty stepper trash/minus toggle) actually re-render
- Fix quantity stepper DOM order in SingleProduct.vue/CartItem.vue so
  plus/minus render correctly under RTL flex
- prisma/assign-downloaded-images.js: seed real product photos (FEATURED/
  FEATURED_MOBILE/GALLERY/GALLERY_MOBILE) onto the 5 placeholder products
2026-09-18 16:22:31 +03:30
Montech 05fe780c89 Merge branch 'dev'
# Conflicts:
#	apps/admin-panel/dist/index.html
#	apps/admin-panel/nginx.conf
#	apps/admin-panel/vite.config.ts
#	apps/api/release/app.js
2026-09-16 15:45:23 +03:30
mahmood 2448627e1b fix: stop drift migration from dropping tracking table 2026-09-15 22:40:00 +03:30
Montech 341c7a5095 fix some for db 2026-09-15 17:25:12 +03:30
s.esmaeiliandClaude Sonnet 5 2b6795d007 api: fix migration runner, serve uploads correctly, add product photos
Three real bugs found and fixed while wiring up product images end-to-end:

1. src/prisma/migrate.ts only discovered flat prisma/migrations/<name>.sql
   files, never Prisma's own folder-per-migration layout
   (<timestamp>_<name>/migration.sql). Every migration created the normal
   way (via 'prisma migrate dev') was silently skipped; only a hand-added
   flat duplicate (prisma/migrations/0001_init.sql, now removed) ever ran.
   This meant schema.prisma had drifted well ahead of what any real deploy
   database actually had (missing columns on City, Customer, Branch,
   Product, several new tables). Fixed to discover both layouts; the
   drift is closed with a new 20260914165255_sync_schema_drift migration.

2. Neither nginx.conf (production) nor vite.config.ts (dev) proxied
   /uploads/ to the API — only /api/. UploadedFile/ProductImage URLs
   (/uploads/<file>, served by main.ts's useStaticAssets OUTSIDE the /api
   prefix) 404'd through both. Both now proxy /uploads/ the same way /api/
   already was.

3. docker-compose.yml's api service had no volume for storage/uploads, so
   every uploaded file — and by extension every ProductImage row pointing
   at one — was lost on the next container recreate/redeploy. Added a
   named volume.

Also: main.ts's static file serving now sets Content-Type: image/avif
explicitly (serve-static's bundled mime table predates .avif and served it
as application/octet-stream; browsers rendered it anyway by sniffing, but
a stricter client would not have).

Product photos: copied 15 real jewelry photos into the uploads volume,
registered them as UploadedFile rows, and assigned each of the 5 existing
Product rows a randomly picked one (duplicates allowed, per request),
replacing their /img/no-items.png placeholder ProductImage row. Verified
end-to-end in a real browser against the real containerized API+DB: logged
in, opened the admin product list, confirmed all 5 rows render their photo
(naturalWidth/Height populated, network 200s, no console errors).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 20:56:17 +03:30
mahmood f19f49daeb feat: auto-run SQL migrations and one-time seed on boot 2026-09-10 17:15:17 +03:30