Updated various project dependencies using `cargo update` or manual checks against crates.io (as of 2025-04-08). Ensures usage of latest bug fixes and security patches. Verified with `cargo check` and `cargo build`.
Learner Management System (LMS) Backend
This is the backend service for the Learner Management System, built with Rust using the Actix Web framework. It provides a RESTful API for the frontend application, handles business logic, interacts with a MariaDB database using SQLx, and implements secure PAKE SRP authentication. The application is designed to be run using Docker and Docker Compose.
Features
- RESTful API: Provides endpoints for authentication, user profiles, admin functions, and potentially course/classroom management in the future.
- Secure Authentication: Implements Password-Authenticated Key Exchange (PAKE) using the Secure Remote Password (SRP-6a) protocol via the
srpcrate. - High Performance: Built with Rust and Actix Web for excellent performance, memory safety, and concurrency.
- Database Interaction: Uses SQLx for asynchronous, compile-time checked SQL queries against MariaDB.
- Database Schema Management: Automatically creates database tables on initial startup if they don't exist.
- Sample Data Population: Populates essential data (e.g., courses, sample users without passwords) on first run.
- Dockerized: Fully containerized using Docker and Docker Compose for easy setup, consistent environments, and deployment.
- Configuration: Configurable via environment variables (
.envfile support). - Modular Structure: Code organized into logical modules (handlers, db, models, errors, config).
- Basic Logging: Uses
env_loggerfor request and application logging.
Technologies Used
- Rust (Stable toolchain)
- Actix Web (v4): High-performance web framework.
- SQLx: Asynchronous SQL toolkit with compile-time query checking.
srpcrate: For SRP-6a protocol implementation.- MariaDB: Relational database (run via Docker).
- Docker & Docker Compose: For containerization and orchestration.
serde: For data serialization/deserialization (JSON).dotenv: For loading environment variables from.envfiles.env_logger: For flexible logging configuration.chrono: For date/time handling.hex: For encoding/decoding SRP values.uuid: For generating session tokens (current implementation).
Prerequisites
- Docker
- Docker Compose (v1 or v2 syntax compatible with the
docker-compose.yml) - Rust Toolchain (Stable - only needed if building/running outside the provided Docker setup)
Getting Started
-
Clone the Repository: Clone the repository containing both the
lms-backendfolder and the maindocker-compose.yml.git clone <your-main-repository-url> cd <your-main-repository-directory> # Should contain lms-backend/ and docker-compose.yml -
Create Environment File: In the root directory (the one containing
docker-compose.yml), create a.envfile to specify database credentials. You can copy the example below or rely on the defaults defined indocker-compose.yml.# .env (in the root directory) # MariaDB Credentials (used by docker-compose to init the DB) MARIADB_ROOT_PASSWORD=supersecretroot MARIADB_DATABASE=lms_db MARIADB_USER=lms_user MARIADB_PASSWORD=lms_password # Backend Configuration (can override defaults) # SERVER_ADDR=0.0.0.0:8080 # Already set in compose file RUST_LOG=info,lms_backend=debug # Example: Set backend log level to debug # SECRET_KEY=your_secret_for_jwt_if_used # Needed if switching to JWT sessions -
Build and Run using Docker Compose: From the root directory, run:
docker-compose up --build -d--build: Forces rebuilding the backend image if code has changed.-d: Runs the containers in detached mode (in the background).- The first run might take some time to download images and build the Rust application.
-
Accessing the API:
- The API should now be running and accessible at
http://localhost:8080. - Test the health check endpoint:
http://localhost:8080/api/health. You should receive a JSON response indicating success.
- The API should now be running and accessible at
-
Stopping the Services:
docker-compose down
Project Structure (lms-backend/src/)
src/
├── main.rs # Entry point, server setup, middleware, routing
├── config.rs # Configuration loading (.env)
├── db.rs # Database logic (SQLx queries, migrations/setup, data population)
├── handlers.rs # Actix route handlers, business logic, API endpoint definitions
├── models.rs # Data structures (DB models, API request/response structs)
└── errors.rs # Custom error types and `ResponseError` implementation
Configuration
Configuration is primarily handled via environment variables, loaded using the dotenv crate during startup within the container. Key variables:
DATABASE_URL: The connection string for MariaDB (automatically constructed indocker-compose.yml).SERVER_ADDR: The address and port the Actix server binds to (e.g.,0.0.0.0:8080).RUST_LOG: Controls logging verbosity (e.g.,info,debug,actix_web=warn,lms_backend=debug).SECRET_KEY: Required if implementing JWT-based sessions in the future.
These variables are typically passed from the host's .env file (if present) or directly set in the environment section of the backend service in docker-compose.yml.
API Endpoints
The following main API endpoints are implemented in src/handlers.rs:
GET /api/health: Health check.POST /api/auth/srp/start: Initiates SRP login (provides salt, server ephemeral).POST /api/auth/srp/verify: Verifies client SRP proof, generates session token on success.POST /api/auth/logout: (Basic) Invalidates session token.GET /api/profile/{user_id}: Retrieves user profile information.PUT /api/profile/settings: Updates user settings (e.g., profile picture).GET /api/admin/dashboard: Gets admin dashboard counts.GET /api/admin/students: Lists students (basic).GET /api/admin/students/{student_id}/financials: Gets (mocked) financial data for a student.
Refer to src/handlers.rs and src/models.rs for detailed request/response structures.
Database
- Type: MariaDB (run via
mariadb:10.11Docker image). - Interaction: Asynchronous queries via
sqlx. - Schema: Defined and created in
src/db.rs::init_db. Tables includestudents,teachers,courses,enrollments. SRP salt and verifier fields replace traditional password hashes. - Persistence: Database data is persisted using a Docker named volume (
mariadb_data) defined indocker-compose.yml. - Initial Data:
src/db.rs::populate_initial_dataadds sample courses and users (students/teachers) without any password/SRP data set. Users cannot log in until a password-setting mechanism is implemented.
Authentication (SRP)
- Uses the PAKE SRP-6a protocol.
- Flow:
- Client sends
userIdto/api/auth/srp/start. - Server looks up user (student or teacher), finds SRP
saltandverifier(if set), generates server ephemeralB, and stores temporary challenge state (in memory). Responds withsalt,B, anduserType. - Client calculates its ephemeral
Aand proofM1, sendsuserId,userType,A,M1to/api/auth/srp/verify. - Server retrieves challenge state, verifies
M1. If valid, calculates server proofM2, generates a session token (UUID), stores session (in memory), and responds withM2and login data (including token). - Client verifies
M2.
- Client sends
Important Notes & TODOs
- 🚨 Production State Management: The current use of
AppState(in-memoryMutex<HashMap>) for storing active SRP challenges and user sessions is NOT suitable for production. It will lose state on restart and doesn't scale. Replace this with a persistent solution like Redis or a dedicated database table for sessions and potentially challenges (with TTL). - 🔐 Authentication Middleware: Protected routes (
/profile/*,/admin/*, etc.) currently lack proper token validation middleware. Implement Actix middleware to verify theAuthorization: Bearer <token>header against the active session store before allowing access. - 🔑 Password Setting/Registration: There is currently no mechanism for users to set their initial password or change it. An endpoint needs to be created that takes a username/password, generates the SRP salt and verifier using
srp::server::generate_verifier, and stores them in the database for the corresponding user. - 🧪 Testing: Implement comprehensive unit and integration tests for handlers, database logic, and authentication flow.
- 📈 Scalability: Consider connection pool tuning (
max_connectionsinmain.rs) and potential optimizations for high-load scenarios. - 📚 API Documentation: Consider generating API documentation (e.g., using OpenAPI specs).