help@rskworld.in +91 93305 39277
RSK World
  • Home
  • Development
    • Web Development
    • Mobile Apps
    • Software
    • Games
    • Project
  • Technologies
    • Data Science
    • AI Development
    • Cloud Development
    • Blockchain
    • Cyber Security
    • Dev Tools
    • Testing Tools
  • About
  • Contact

Theme Settings

Color Scheme
Display Options
Font Size
100%
Back to Project
RSK World
rust-web-server
/
src
RSK World
rust-web-server
Rust Web Server - High-Performance Async Web Server + WebSocket Support + JWT Authentication + File Upload + Memory Safety + Educational Design
src
  • auth.rs15.7 KB
  • config.rs2.9 KB
  • error.rs5.2 KB
  • file_upload.rs19 KB
  • handlers.rs12.8 KB
  • lib.rs1.8 KB
  • main.rs6 KB
  • middleware.rs6.2 KB
  • static_files.rs9.9 KB
  • utils.rs9.6 KB
  • websocket.rs15.3 KB
SECURITY.mdstatic_files.rs
SECURITY.md
Raw Download

SECURITY.md

# Security Policy

## 🔒 Security Overview

The Rust Web Server is built with security in mind, leveraging Rust's memory safety guarantees and following security best practices.

## 🚨 Reporting Security Vulnerabilities

If you discover a security vulnerability, please report it responsibly:

**DO NOT** create public GitHub issues for security vulnerabilities.

### Contact

Please report security vulnerabilities by emailing:
- **Security Team**: security@rskworld.in
- **Primary Contact**: hello@rskworld.in

### What to Include

When reporting a vulnerability, please include:

- A clear description of the vulnerability
- Steps to reproduce the issue
- Potential impact and severity
- Any suggested fixes or mitigations

### Response Timeline

We will acknowledge your report within 48 hours and provide a more detailed response within 7 days indicating our next steps.

We will keep you informed about our progress throughout the process of fixing the vulnerability.

## 🛡️ Security Measures

### Memory Safety
- Rust's ownership system prevents common memory bugs
- No garbage collection overhead
- Thread safety guarantees

### Input Validation
- Request size limits
- Path traversal protection
- Content type validation

### Authentication & Authorization
- JWT-based authentication (when enabled)
- Role-based access control
- Secure password hashing with bcrypt

### HTTPS Support
- SSL/TLS configuration support
- Certificate validation

### Security Headers
- XSS protection
- Content type options
- CORS configuration

## 🔧 Security Configuration

### Environment Variables

Set these environment variables for enhanced security:

```bash
# JWT Secret (change this!)
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production

# SSL/TLS
SSL_CERT_PATH=certs/server.crt
SSL_KEY_PATH=certs/server.key
```

### Configuration File

```toml
[ssl]
enabled = true
cert_path = "certs/server.crt"
key_path = "certs/server.key"

[auth]
enabled = true
jwt_secret = "your-secret-key-here"
token_expiry_hours = 24
```

## 📋 Security Checklist

### Development
- [ ] Run `cargo audit` regularly to check for vulnerable dependencies
- [ ] Use `cargo clippy` with security lints enabled
- [ ] Review code for common vulnerabilities (OWASP Top 10)
- [ ] Use parameterized queries for database operations

### Deployment
- [ ] Use HTTPS in production
- [ ] Keep dependencies updated
- [ ] Use strong, unique secrets
- [ ] Implement rate limiting
- [ ] Enable security headers
- [ ] Regular security audits

### Monitoring
- [ ] Monitor for suspicious activity
- [ ] Log security events
- [ ] Implement intrusion detection
- [ ] Regular backup and recovery testing

## 🔄 Security Updates

Security updates will be released as patch versions with the prefix "security" in commit messages and release notes.

Subscribe to security advisories:
- GitHub Security Advisories
- RSS feed for releases
- Email notifications for critical updates

## 📞 Contact Information

**RSK World Security Team**
- Email: security@rskworld.in
- Website: https://rskworld.in
- Phone: +91 93305 39277

---

**© 2026 RSK World. All rights reserved.**
src/static_files.rs
Raw Download
Find: Go to:
/*
 * Static File Serving Module - Rust Web Server
 * 
 * Created by RSK World (https://rskworld.in)
 * Founder: Molla Samser
 * Designer & Tester: Rima Khatun
 * 
 * Contact:
 * - Email: hello@rskworld.in, support@rskworld.in
 * - Phone: +91 93305 39277
 * - Address: Nutanhat, Mongolkote, Purba Burdwan, West Bengal, India, 713147
 * 
 * © 2026 RSK World. All rights reserved.
 * Content used for educational purposes only.
 */

use hyper::{Body, Response, StatusCode};
use mime_guess::from_path;
use std::path::{Path, PathBuf};
use tokio::fs;
use tracing::{debug, error, warn};

use crate::error::{ServerError, ServerResult};

/// Static file handler
pub struct StaticFileHandler {
    base_dir: PathBuf,
}

impl StaticFileHandler {
    /// Create a new static file handler
    pub fn new(base_dir: PathBuf) -> Self {
        Self { base_dir }
    }

    /// Serve a static file
    pub async fn serve_file(&self, file_path: &str) -> ServerResult<Response<Body>> {
        let full_path = self.get_full_path(file_path)?;
        
        // Security check: ensure the path is within the base directory
        if !self.is_safe_path(&full_path) {
            warn!("Attempted to access file outside base directory: {:?}", full_path);
            return Err(ServerError::Forbidden("Access denied".to_string()));
        }

        debug!("Serving static file: {:?}", full_path);

        // Check if file exists
        if !full_path.exists() {
            return Err(ServerError::NotFound(format!("File not found: {}", file_path)));
        }

        // Check if it's a directory
        if full_path.is_dir() {
            // Try to serve index.html
            let index_path = full_path.join("index.html");
            if index_path.exists() {
                return self.serve_file_content(&index_path).await;
            } else {
                return Err(ServerError::NotFound("Directory listing not allowed".to_string()));
            }
        }

        // Serve the file
        self.serve_file_content(&full_path).await
    }

    /// Serve file content
    async fn serve_file_content(&self, file_path: &Path) -> ServerResult<Response<Body>> {
        // Read file content
        let content = fs::read(file_path).await
            .map_err(|e| ServerError::StaticFile(format!("Failed to read file: {}", e)))?;

        // Determine MIME type
        let mime_type = from_path(file_path)
            .first_or_octet_stream()
            .to_string();

        // Create response
        let mut response = Response::builder()
            .status(StatusCode::OK)
            .header("content-type", mime_type)
            .body(Body::from(content))
            .map_err(|e| ServerError::Internal(format!("Failed to create response: {}", e)))?;

        // Add cache headers for static files
        let headers = response.headers_mut();
        match headers.insert("cache-control", "public, max-age=3600".parse()) {
            Ok(_) => {},
            Err(_) => warn!("Failed to insert cache-control header"),
        }
        match headers.insert("etag", format!("\"{}\"", self.calculate_etag(&content)).parse()) {
            Ok(_) => {},
            Err(_) => warn!("Failed to insert etag header"),
        }

        Ok(response)
    }

    /// Get full path for a relative file path
    fn get_full_path(&self, file_path: &str) -> ServerResult<PathBuf> {
        let path = PathBuf::from(file_path);
        
        // Remove leading slash if present
        let relative_path = if path.starts_with("/") {
            path.strip_prefix("/").unwrap()
        } else {
            path.as_path()
        };

        let full_path = self.base_dir.join(relative_path);
        
        // Convert to absolute path
        match full_path.canonicalize() {
            Ok(path) => Ok(path),
            Err(_) => Ok(full_path), // Return original path if canonicalization fails
        }
    }

    /// Check if a path is safe (within base directory)
    fn is_safe_path(&self, full_path: &Path) -> bool {
        match self.base_dir.canonicalize() {
            Ok(base_canonical) => {
                match full_path.canonicalize() {
                    Ok(path_canonical) => {
                        path_canonical.starts_with(&base_canonical)
                    }
                    Err(_) => {
                        // If we can't canonicalize, do a simple prefix check
                        full_path.starts_with(&self.base_dir)
                    }
                }
            }
            Err(_) => true, // If base dir can't be canonicalized, assume safe
        }
    }

    /// Calculate ETag for file content
    fn calculate_etag(&self, content: &[u8]) -> String {
        use std::hash::{Hash, Hasher};
        use std::collections::hash_map::DefaultHasher;
        
        let mut hasher = DefaultHasher::new();
        content.hash(&mut hasher);
        format!("{:x}", hasher.finish())
    }

    /// Check if file has been modified based on If-None-Match header
    pub fn is_not_modified(&self, etag: &str, if_none_match: Option<&str>) -> bool {
        match if_none_match {
            Some(header_etag) => header_etag == etag,
            None => false,
        }
    }

    /// Handle conditional GET requests
    pub async fn serve_file_conditional(
        &self,
        file_path: &str,
        if_none_match: Option<&str>,
    ) -> ServerResult<Response<Body>> {
        let full_path = self.get_full_path(file_path)?;
        
        if !self.is_safe_path(&full_path) {
            return Err(ServerError::Forbidden("Access denied".to_string()));
        }

        if !full_path.exists() {
            return Err(ServerError::NotFound(format!("File not found: {}", file_path)));
        }

        // Read file content to calculate ETag
        let content = fs::read(&full_path).await
            .map_err(|e| ServerError::StaticFile(format!("Failed to read file: {}", e)))?;

        let etag = format!("\"{}\"", self.calculate_etag(&content));

        // Check if file has not been modified
        if self.is_not_modified(&etag, if_none_match) {
            return Ok(Response::builder()
                .status(StatusCode::NOT_MODIFIED)
                .header("etag", etag)
                .body(Body::empty())
                .map_err(|e| ServerError::Internal(format!("Failed to create response: {}", e)))?);
        }

        // Serve the file with ETag header
        let mime_type = from_path(&full_path)
            .first_or_octet_stream()
            .to_string();

        let mut response = Response::builder()
            .status(StatusCode::OK)
            .header("content-type", mime_type)
            .header("etag", etag)
            .header("cache-control", "public, max-age=3600")
            .body(Body::from(content))
            .map_err(|e| ServerError::Internal(format!("Failed to create response: {}", e)))?;

        Ok(response)
    }

    /// Create default static files directory structure
    pub async fn create_default_structure(&self) -> ServerResult<()> {
        let dirs = vec![
            self.base_dir.join("css"),
            self.base_dir.join("js"),
            self.base_dir.join("images"),
            self.base_dir.join("fonts"),
        ];

        for dir in dirs {
            if !dir.exists() {
                fs::create_dir_all(&dir).await
                    .map_err(|e| ServerError::StaticFile(format!("Failed to create directory: {}", e)))?;
                debug!("Created directory: {:?}", dir);
            }
        }

        // Create a default index.html if it doesn't exist
        let index_path = self.base_dir.join("index.html");
        if !index_path.exists() {
            let default_html = r#"<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Welcome to Rust Web Server</title>
    <style>
        body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
        .container { text-align: center; }
        .logo { font-size: 4em; margin: 20px 0; }
    </style>
</head>
<body>
    <div class="container">
        <div class="logo">🦀</div>
        <h1>Welcome to Rust Web Server</h1>
        <p>High-performance web server built with Rust</p>
        <p>Created by <strong>RSK World</strong></p>
    </div>
</body>
</html>"#;

            fs::write(&index_path, default_html).await
                .map_err(|e| ServerError::StaticFile(format!("Failed to create index.html: {}", e)))?;
            debug!("Created default index.html");
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::TempDir;

    #[tokio::test]
    async fn test_static_file_handler() {
        let temp_dir = TempDir::new().unwrap();
        let handler = StaticFileHandler::new(temp_dir.path().to_path_buf());

        // Create a test file
        let test_file = temp_dir.path().join("test.txt");
        fs::write(&test_file, "Hello, World!").await.unwrap();

        // Test serving the file
        let response = handler.serve_file("test.txt").await.unwrap();
        assert_eq!(response.status(), StatusCode::OK);

        // Test non-existent file
        let result = handler.serve_file("nonexistent.txt").await;
        assert!(result.is_err());
    }

    #[test]
    fn test_safe_path() {
        let temp_dir = TempDir::new().unwrap();
        let handler = StaticFileHandler::new(temp_dir.path().to_path_buf());

        // Test safe path
        let safe_path = temp_dir.path().join("safe.txt");
        assert!(handler.is_safe_path(&safe_path));

        // Test unsafe path (would need to be outside base dir in real scenario)
        // This is a simplified test - in practice, you'd need to create an actual unsafe path
    }
}
290 lines•9.9 KB
rust

About RSK World

Founded by Molla Samser, with Designer & Tester Rima Khatun, RSK World is your one-stop destination for free programming resources, source code, and development tools.

Founder: Molla Samser
Designer & Tester: Rima Khatun

Development

  • Game Development
  • Web Development
  • Mobile Development
  • AI Development
  • Development Tools

Legal

  • Terms & Conditions
  • Privacy Policy
  • Disclaimer

Contact Info

Nutanhat, Mongolkote
Purba Burdwan, West Bengal
India, 713147

+91 93305 39277

hello@rskworld.in
support@rskworld.in

© 2026 RSK World. All rights reserved.

Content used for educational purposes only. View Disclaimer