Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

42 Commits
 
 
 
 
 
 
 
 

Repository files navigation

JV Shetty Megamart — Campus E-Commerce Platform

A production-grade campus supermarket for BITS Pilani Goa with OTP-based authentication, JWT sessions, and Role-Based Access Control (RBAC).


Project Overview

JV Shetty Megamart is a full-stack PHP e-commerce platform built exclusively for the BITS Pilani Goa campus community. It enforces campus-email login (@goa.bits-pilani.ac.in), time-boxed store hours (4 – 9 PM IST), and a multi-role permission model so that students, faculty, admins, and delivery partners each see only what they are allowed to.

Key capabilities:

  • Browse and search the product catalogue with category / price filters.
  • Cart, checkout, order tracking, and cancellation workflows.
  • Admin panel: order management, inventory control, analytics, role management.
  • Delivery portal for fulfilment partners.
  • OTP-verified login with JWT bearer tokens (no persistent passwords on the wire).

Security Features

Feature Detail
OTP TTL 10 minutes (600 s) — OTPs expire automatically
OTP rate limit 3 requests per hour per email address (atomic Redis sliding window via Lua)
Brute-force lockout 5 failed verification attempts → account locked for 1 hour
JWT session length 30 minutes (1 800 s, JWT_TTL)
JWT algorithm HS256 (JWT_ALGORITHM)
OTP hashing bcrypt (password_hash / password_verify)
Campus restriction Only @goa.bits-pilani.ac.in addresses are accepted
Security headers CSP (nonce-based), X-Frame-Options: DENY, HSTS, X-Content-Type-Options, Referrer-Policy
Input sanitisation NULL-byte stripping, control-char removal, 65 535-byte truncation
SQL injection guard Prepared statements everywhere; request-level alerting via SecurityMiddleware

Repository Structure

JV-Shetty/
├── jv_shetty/                   # Application root (Apache document root)
│   ├── auth/                    # New OTP + JWT + RBAC auth system
│   │   ├── AuthService.php      # Orchestration: OTP → email → JWT
│   │   ├── JWTHandler.php       # Pure-PHP HS256 JWT (no external library)
│   │   ├── OTPManager.php       # OTP lifecycle, rate-limiting, locking
│   │   ├── RBACManager.php      # Permission map + enforcement helpers
│   │   ├── RedisClientInterface.php
│   │   ├── RedisFactory.php     # Redis connection + adapter
│   │   └── middleware/
│   │       ├── JWTMiddleware.php      # Bearer-token verification
│   │       ├── RBACMiddleware.php     # JWT + role/permission gate
│   │       └── SecurityMiddleware.php # Security headers, input sanitise
│   ├── api/                     # REST API endpoints
│   ├── config/                  # App, DB, JWT, Redis config
│   ├── core/                    # Legacy Auth (session), Validator, Response…
│   ├── models/                  # Cart, Order, Product, User models
│   ├── admin/                   # Admin panel pages
│   ├── tests/                   # PHPUnit test suite
│   │   ├── phpunit.xml
│   │   ├── bootstrap.php
│   │   ├── OTPBoundaryTest.php        # Boundary / unit tests (original)
│   │   ├── ExtendedCoverageTest.php   # Extended coverage (new)
│   │   ├── IntegrationJourneyTest.php # End-to-end journey (new)
│   │   └── stubs/
│   │       ├── RedisStub.php
│   │       └── DatabaseStub.php
│   └── *.php                    # Customer-facing pages
└── README.md                    # This file

Setup Guide

Prerequisites

Requirement Version
PHP ≥ 8.1
MySQL ≥ 8.0
Redis ≥ 6.0
Apache ≥ 2.4 (with mod_rewrite)
Composer ≥ 2 (for PHPMailer)

1 — Clone and install dependencies

git clone https://github.com/Otto-Deviant1904/JV-Shetty.git
cd JV-Shetty/jv_shetty
composer install

2 — Configure environment variables

Copy .env.example to .env and fill in every value:

# ── MySQL ─────────────────────────────────────────────────────────────────────
DB_HOST=127.0.0.1
DB_NAME=jv_shetty_db
DB_USER=jvuser
DB_PASS=strongpassword

# ── Redis ─────────────────────────────────────────────────────────────────────
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASS=
REDIS_DB=0

# ── JWT ───────────────────────────────────────────────────────────────────────
# Must be at least 32 random characters — never commit the real value.
JWT_SECRET=replace-with-a-64-char-random-string

# ── SMTP (for OTP delivery) ───────────────────────────────────────────────────
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USERNAME=you@gmail.com
SMTP_PASSWORD=app-password
SMTP_FROM_EMAIL=noreply@jvshetty.bitsgoa.ac.in
SMTP_FROM_NAME=JV Shetty Store

# ── App ───────────────────────────────────────────────────────────────────────
BASE_URL=http://localhost/jv_shetty
RATE_LIMIT_ENABLED=true

Security noteJWT_SECRET is loaded by config/jwt.php. Set it via your web-server's environment (SetEnv in Apache, fastcgi_param in nginx) and never hard-code it in source files.

3 — Database migration

# Base schema (products, users, roles, orders, etc.)
mysql -u jvuser -p jv_shetty_db < jv_shetty/database/schema.sql

# OTP auth tables (otp_codes + audit_log additions)
mysql -u jvuser -p jv_shetty_db < jv_shetty/database/migrations/002_otp_auth.sql

4 — Web server

Point the document root to jv_shetty/ and enable mod_rewrite:

<VirtualHost *:80>
    DocumentRoot /var/www/html/JV-Shetty/jv_shetty
    DirectoryIndex index.php

    <Directory /var/www/html/JV-Shetty/jv_shetty>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

API Endpoints

All API responses use Content-Type: application/json.

Authentication (OTP flow)

Method URL Description
POST /api/auth.php?action=request_otp Request a 6-digit OTP (campus email required)
POST /api/auth.php?action=verify_otp Submit OTP → receive JWT
POST /api/auth.php?action=logout Invalidate session
GET /api/auth.php?action=me Return current authenticated user

Request OTP

POST /api/auth.php?action=request_otp
{ "email": "f20230001@goa.bits-pilani.ac.in" }
200 { "success": true, "message": "OTP sent to your email address." }
422 { "success": false, "message": "Only BITS Goa campus emails are allowed." }
429 { "success": false, "message": "Too many OTP requests. Please wait before requesting another OTP." }
423 { "success": false, "message": "Account is locked due to too many failed attempts." }

Verify OTP

POST /api/auth.php?action=verify_otp
{ "email": "f20230001@goa.bits-pilani.ac.in", "otp": "482931" }
200 { "success": true, "token": "eyJ...", "user": { "id": 1, "email": "...", "role": "student" } }
401 { "success": false, "message": "Invalid OTP. 3 attempt(s) remaining." }
410 { "success": false, "message": "OTP has expired. Please request a new one." }

Products

Method URL Auth Description
GET /api/products.php List / search products
GET /api/products.php?action=detail&id=X Product detail
POST /api/products.php?action=create admin Create product
POST /api/products.php?action=update&id=X admin Update product
POST /api/products.php?action=delete&id=X admin Delete product

Cart

Method URL Auth Description
GET /api/cart.php?action=get user Get cart contents
POST /api/cart.php?action=add user Add item
POST /api/cart.php?action=update user Update quantity
POST /api/cart.php?action=remove user Remove item
POST /api/cart.php?action=clear user Clear cart

Orders

Method URL Auth Description
GET /api/orders.php user List own orders
POST /api/orders.php?action=create user Place order
GET /api/orders.php?action=detail&id=X user Order detail
POST /api/orders.php?action=update_status admin Update order status
POST /api/orders.php?action=cancel user Cancel order

Using JWT on protected endpoints

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Or via the custom header:

X-Auth-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

RBAC Roles & Permissions

Role Key Permissions
super_admin Wildcard * — everything
admin view/manage users, products, orders, reports, settings, audit logs
faculty view products, place order, view own orders, manage profile
student view products, place order, view own orders, manage profile
customer view products, place order, view own orders, manage profile
delivery_partner view assigned orders, update delivery status, manage profile
// At the top of any protected endpoint:

// Any authenticated user
$claims = JWTMiddleware::handle();

// Admin or super_admin only
$claims = RBACMiddleware::handle(['admin', 'super_admin']);

// Require a specific permission
$claims = RBACMiddleware::requirePermission('manage_products');

// Non-aborting check (returns null on failure)
$claims = RBACMiddleware::check(['admin']);

Testing

Unit & integration tests (PHPUnit)

# Install PHPUnit (if not already via Composer)
cd jv_shetty
composer require --dev phpunit/phpunit ^8

# Run the full suite (no MySQL or Redis needed — SQLite + in-process stubs)
cd tests
phpunit --configuration phpunit.xml

Expected output:

PHPUnit 8.x.x

OTPBoundaryTest        ........... (24 tests)
ExtendedCoverageTest   ........... (55+ tests, fills AuthService / JWT /
                                    OTPManager / RBAC / middleware gaps)
IntegrationJourneyTest ........... (full user journey + incompatibility docs)

OK (XX tests, YY assertions)

What each suite covers

File Coverage
OTPBoundaryTest.php OTP TTL boundaries, rate-limit boundaries, brute-force lockout, JWT expiry/tamper, RBAC basics, SecurityMiddleware detection
ExtendedCoverageTest.php AuthService flows, all JWTHandler error paths (structure, alg, nbf, iss, aud), OTPManager state machine, full verifyOTP() paths, RBACManager edge cases, JWTMiddleware header extraction, RBACMiddleware check(), SecurityMiddleware nonce / jsonSafe / deep-sanitize
IntegrationJourneyTest.php End-to-end: OTP request → verification → JWT → protected route → RBAC enforcement; rate-limit and brute-force scenarios; documented incompatibility between legacy session auth and JWTMiddleware

⚠ Incompatibility note

The legacy PHP pages (api/cart.php, profile.php, checkout.php, etc.) use Auth::requireAuth() which enforces PHP session authentication ($_SESSION['logged_in']). The new JWTMiddleware authenticates via Bearer tokens stored in $_REQUEST['_jwt_claims'].

These two mechanisms are orthogonal. A user who authenticates via the OTP flow and receives a JWT will be rejected by every legacy page that calls Auth::requireAuth(), and vice-versa. Until both sides are unified behind a single auth layer, pages that must support JWT-authenticated users must be updated to check $_REQUEST['_jwt_claims'] in addition to (or instead of) $_SESSION['logged_in'].

Files that need updating:

File Issue
api/cart.php Calls Auth::requireAuth() → session redirect
api/orders.php Calls Auth::requireAuth() → session redirect
api/user.php Calls Auth::check() → session check
api/wishlist.php Calls Auth::requireAuth() → session redirect
profile.php Calls Auth::requireAuth() → session redirect
cart.php Calls Auth::requireAuth() → session redirect
checkout.php Calls Auth::requireAuth() → session redirect
orders.php Calls Auth::requireAuth() → session redirect
wishlist.php Calls Auth::requireAuth() → session redirect

Contributing

  1. Branch from main.
  2. Run the PHPUnit suite before opening a PR.
  3. New auth features must be covered by unit tests in tests/.
  4. Never commit secrets — use environment variables.

JV Shetty Megamart — Campus supermarket for BITS Pilani Goa.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages