2025-04-08 04:53:16 +08:00
2025-04-08 04:53:16 +08:00
2025-04-08 04:53:16 +08:00
2025-04-08 04:45:00 +08:00
2025-04-08 04:53:16 +08:00
2025-04-08 04:53:16 +08:00
2025-04-08 04:53:16 +08:00
2025-04-08 03:56:43 +08:00
2025-04-08 03:59:51 +08:00

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 srp crate.
  • 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 (.env file support).
  • Modular Structure: Code organized into logical modules (handlers, db, models, errors, config).
  • Basic Logging: Uses env_logger for 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.
  • srp crate: 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 .env files.
  • 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

  1. Clone the Repository: Clone the repository containing both the lms-backend folder and the main docker-compose.yml.

    git clone <your-main-repository-url>
    cd <your-main-repository-directory> # Should contain lms-backend/ and docker-compose.yml
    
  2. Create Environment File: In the root directory (the one containing docker-compose.yml), create a .env file to specify database credentials. You can copy the example below or rely on the defaults defined in docker-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
    
  3. 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.
  4. 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.
  5. 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 in docker-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.11 Docker image).
  • Interaction: Asynchronous queries via sqlx.
  • Schema: Defined and created in src/db.rs::init_db. Tables include students, 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 in docker-compose.yml.
  • Initial Data: src/db.rs::populate_initial_data adds 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:
    1. Client sends userId to /api/auth/srp/start.
    2. Server looks up user (student or teacher), finds SRP salt and verifier (if set), generates server ephemeral B, and stores temporary challenge state (in memory). Responds with salt, B, and userType.
    3. Client calculates its ephemeral A and proof M1, sends userId, userType, A, M1 to /api/auth/srp/verify.
    4. Server retrieves challenge state, verifies M1. If valid, calculates server proof M2, generates a session token (UUID), stores session (in memory), and responds with M2 and login data (including token).
    5. Client verifies M2.

Important Notes & TODOs

  • 🚨 Production State Management: The current use of AppState (in-memory Mutex<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 the Authorization: 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_connections in main.rs) and potential optimizations for high-load scenarios.
  • 📚 API Documentation: Consider generating API documentation (e.g., using OpenAPI specs).

Contributing

License

Description
A learner management system made by WIT students, using Rust Actix
Readme MIT 49 KiB
Languages
Rust 95.4%
Dockerfile 4.6%