Files
BarangaySystem/ai-docs/audit-2026-05-14-190110.md
2026-06-06 18:43:00 +08:00

117 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Store Owner Audit — 2026-05-14 19:01:10 UTC
Running notes from the Store Owner accessible-pages audit. Bugs we
have already fixed are listed first for traceability; the open items
below are not yet patched and need a follow-up decision before merge.
## Fixed (commit b4defbe + this batch)
### Erratic table names (Hypervel surfaces these as empty 400s)
- `app/Http/Controllers/Market/ProductController.php:766`
`pluck('stores.hashkey')``pluck('str.hashkey')`. Drove the
Manage Listings modal in `ManageProductsAdmin.vue` to fail on every
open.
- `app/Http/Controllers/Market/BatchController.php:91`
`where('products.id', …)``where('prd_items.id', …)`. Broke the
"already attached to this store" check in batch-import (existing
mode).
### Validation/permission walls
- `ProductController::editProductAdmin` required `ModifyAllProducts`
(Big-3 only) even when `data.store_hash` was supplied. STORE_OWNER
edits via `UpdateProductModal.vue` returned 401. Now per-store
edits only need `ModifyOwnProduct` / `AddProducttoOwnStore` plus
the existing ownership branch.
- `ProductController::toggleProductStatus_Admin` — same gate, same
relaxation.
- `ProductController::deleteProduct_Admin` required
`DeleteAllProducts` (Big-3 only). Now accepts `DeleteOwnProduct`
and the ancestor-of-creator path so owners can delete products
they created.
- `PosController::voidSession` had no authorization check at all.
Any session_hash could void any session. Now gated by
`UserPermissions::isUserAllowedAccessToStore`.
- `PosAccessKeyController::destroy` and `toggleStatus` only checked
the action permission. Now also verify the key belongs to a store
the caller owns/manages.
- `StoreController::autoCreate` had no RBAC. Now requires
Big-3 or STORE_OWNER, and dedupes generated names against the
globally unique `str.name` index by appending a short suffix.
- `HomeStoreOwner.vue` referenced an undefined `creatingStore` ref
(the actual ref is `creatingQuickStore`) — the "Creating your
store..." spinner never rendered.
### BatchAddProducts opened to STORE_OWNER with guardrails
- `BatchController::batchCreateProducts` now allows STORE_OWNER, but
only when `target_store_hash` is provided AND the target store is
owned (or managed) by the caller. Without it the call is rejected
up-front instead of silently 401-ing partway through the loop.
- New-mode rows are rejected when a global product with the same
name (case-insensitive, trimmed) already exists. Owners are
expected to pick the existing one via the fuzzy-search modal.
- `BatchAddProducts.vue` now redirects STORE_OWNER to CreateStore via
a yes/no modal when they have zero selectable stores, and refuses
submit if no target store is picked.
## Open — not yet patched, decide before merging
### `editStoreDetails` data leak (medium)
- File: `app/Http/Controllers/Market/StoreController.php:455`
- Route: `POST /Edit/Store/Details/data`
(`routes/web.php:468-474`, middleware `auth + module:stores`).
- Behavior: looks up a `str` row by `hashkey`, and returns
`name`, `category`, `subcategory`, `description`, `address`,
`remarks`, `status`, `is_active`, `photourl`,
`owner.hashkey`, `manager.hashkey`, all `store_managers` user
hashkeys, all linked cooperative hashkeys, the parent-user
selector list, and the dropzone payload — **without** any
authorization check against the caller. Any authenticated user
can issue this POST with any store's hashkey and get back the
owner/manager/coop graph plus internal remarks. There is no
modification path here, so this is information disclosure rather
than escalation, but `remarks` is explicitly marked internal in
the CreateStore flow and the manager/cooperative hashkeys leak
the org graph.
- Suggested fix: require Big-3 OR
(`store->owner_id`/`manager_id` matches caller)
OR caller appears in `store_managers` pivot
OR caller is ancestor of any of the above
(the same predicate used by `canUserAccessPos` /
`isUserAllowedAccessToStore`). Strip `remarks` from the response
for non-Big-3.
- Status: **NOT FIXED IN THIS COMMIT.** Awaiting decision on
whether to (a) tighten the endpoint and accept the chance of
breaking any external/legacy caller, or (b) keep the
read-anybody behavior and only strip `remarks`.
### Other observations (not bugs strictly)
- `editProductAdminByStore` (`ProductController.php:494`) has a
`TODO Check first if store_id is owned by current user` comment
and modifies the global product directly. Currently nothing
routes to it, but leaving it in the codebase is a footgun if
someone wires it up later. Recommend deleting.
- `listProducts_Admin` scopes non-Big-3 by `created_by`, so a
store owner who attached a Big-3-created global product into
their store cannot see/manage that product from "My Products".
Per dictionary L265 this is intentional, but it does mean
store-listings management for owners is split between
"My Products" (creator-scoped) and the per-store flows
(`AddProductsToStore`, `ManageStoresAdmin`).
- The Store Owner home's "Import Products" tile (`pagename:
BatchAddProducts`) now works for STORE_OWNER thanks to the
BatchController relaxation above. Pre-fix this would have
loaded the page and then 401-ed on submit.
## Stores accessed during this audit
- `StoreController` (full file)
- `ProductController` (full file)
- `BatchController` (lines 33172)
- `PosController` (sample around startSession/voidSession/getTodayStats)
- `PosAccessKeyController` (full file)
- Pages: `HomeStoreOwner.vue`, `CreateProductStoreOwner.vue`,
`CreateStore.vue`, `AddProductsToStore.vue`, `BatchAddProducts.vue`,
`ManageProductAdmin.vue`, `ManageProductsAdmin.vue`,
`ManageStoresAdmin.vue`, `PosAccessKeys.vue`,
`UpdateProductModal.vue`
- Routes: `routes/web.php` (home-data + Store/Product/POS blocks)