https://github.com/tkwonn/text-snippet
Backend Project #4
https://github.com/tkwonn/text-snippet
dynamic-website mysql
Last synced: about 1 month ago
JSON representation
Backend Project #4
- Host: GitHub
- URL: https://github.com/tkwonn/text-snippet
- Owner: tkwonn
- Created: 2024-12-27T03:29:46.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-03-17T00:58:13.000Z (about 1 year ago)
- Last Synced: 2025-06-09T22:38:57.976Z (12 months ago)
- Topics: dynamic-website, mysql
- Language: PHP
- Homepage: https://text-snippet.taesokkwon.com
- Size: 153 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Text Snippet Sharing Service
[](https://github.com/tkwonn/text-snippet/commits/)
[](https://github.com/tkwonn/text-snippet/actions/workflows/ci.yml)
[](https://github.com/tkwonn/text-snippet/actions/workflows/cd.yml)
## Table of Contents
- [About](#-about)
- [Demo](#-demo)
- [Built with](#️-built-with)
- [Database Schema](#️-database-schema)
- [Cloud Architecture Diagram](#️-cloud-architecture-diagram)
- [Security Measures](#️-security-measures)
- [CI/CD](#-cicd)
- [How to use](#-how-to-use)
## 💡 About
Similar to Pastebin, this web application allows users to share plain text and code snippets without requiring a user account.
It's useful in the following situations:
- Save frequently used code
- Share code snippets with others
- Refer to code shared by others
**URL**: [text-snippet.taesokkwon.com](https://text-snippet.taesokkwon.com)
## 🎨 Demo
https://github.com/user-attachments/assets/32981ce4-cebb-4b1e-be96-f69ac39c033a
The paste is no longer available after the expiration time.
https://github.com/user-attachments/assets/06f831ea-99c5-436a-a176-6b422752ac2b
## 🏗️ Built with
| **Category** | **Technology** |
|--------------|-----------------------------------------------------------------------------------------------------------------------|
| VM | Amazon EC2 |
| Web server | Nginx |
| Frontend | HTML, JavaScript, Bootstrap CSS |
| Backend | PHP 8.3 |
| Database | Amazon RDS (MySQL 8.0) |
| Middleware | [Custom-built migration tool](https://github.com/tkwonn/text-snippet/blob/main/docs/migration-tool.md) |
| CI/CD | GitHub Actions |
| QA/Testing | - PHP CS Fixer (code formatting)
- PHPStan (linter)
- PHPUnit (unit testing) |
| Tools | Monaco Editor |
| Container | Docker (for local development) |
## 🗄️ Database Schema

## 🏛️ Cloud Architecture Diagram

## 🛡️ Security Measures
#### 1. HTTP Method Restriction
The application checks content size before submission. If the content size exceeds the limit, the application will return an error message. This feature prevents users from submitting excessively large content.
```php
// php ini configuration
post_max_size = 8M
memory_limit = 128M
max_input_time = 60
max_execution_time = 30
```

For testing, `post_max_size` was intentionally set to a low limit (2KB) to verify the validation functionality. In production, the limit is set to 8MB to accommodate larger code snippets while still protecting against potential abuse.
#### 2. Input Sanitization and Character Escaping
- Special characters (`\n`, `\t`, `\'`, `\"`, `\`) are properly escaped/unescaped using PHP's `json_encode()` and `json_decode()` methods.
- All database inputs are parameterized using `mysqli` prepared statements to prevent SQL injection.
- HTML special characters are escaped using `htmlspecialchars()` when displaying titles and metadata.
#### 3. Rate Limiting for DoS Protection
The application limits requests based on the client's IP address.
```
// Nginx configuration
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/m;
server {
listen 80;
server_name localhost;
root /var/www/html/public;
index index.php index.html index.htm;
...
location = /api/paste {
limit_req zone=one;
try_files $uri $uri/ /index.php?$query_string;
}
...
}
```
For testing, the rate limit was intentionally set to a low value (2 requests per minute + no burst) to verify the rate-limiting functionality. In production, the limit is set to 10 requests per minute (+ burst=5 nodelay) to accommodate normal API usage while protecting against potential abuse.
https://github.com/user-attachments/assets/b9840b95-15ae-49cd-9e4b-5991fbc897ec
#### 4. Secure URL generation
Each paste's URL (`https://{domain}/{hash_id}`) is generated using a cryptographically secure random ID via PHP's `random_bytes()` function.
This implementation follows [Latacora's Cryptographic Right Answers](https://www.latacora.com/blog/2018/04/03/cryptographic-right-answers/) and utilizes `/dev/urandom`.
The implementation uses:
- A character set of 64 characters for URL-safe encoding
- 8 characters length for the final hash
- Total possible combinations: 64⁸ = 281,474,976,710,656
## 🚀 CI/CD
This project uses **GitHub Actions** for two separate workflows:
### Continuous Integration (CI)
Located in [`.github/workflows/ci.yml`](.github/workflows/ci.yml), the **CI** workflow runs on pushes to the `main` branch (and other specified triggers). It:
- Installs and caches dependencies via Composer
- Performs **PHP CS Fixer** checks for code style
- Performs **PHPStan** static analysis for code quality
- Runs **PHPUnit** unit tests to verify functionality
### Continuous Deployment (CD)
Located in [`.github/workflows/cd.yml`](.github/workflows/cd.yml), the **CD** workflow is triggered automatically **only if the CI workflow succeeds**. It:
- Uses GitHub Actions OpenID Connect to assume a short-lived AWS role
- Runs commands remotely via **AWS Systems Manager (SSM)** to pull and deploy changes on the EC2 instance (no direct SSH access or security group changes)
- Updates Composer dependencies on the server and restarts services (PHP-FPM, Nginx)
## 📄 How to use
This project uses Docker for local development, making it easy for anyone to run and test the application on their local machine.
1. Clone this repository
```bash
git clone https://github.com/tkwonn/text-snippet.git
cd text-snippet
```
2. Setup the environment variables
```bash
# Copy the example environment file
cp .env.example .env
# Example of .env file content
DATABASE_HOST=mysql
DATABASE_NAME=pastes
DATABASE_USER=user
DATABASE_USER_PASSWORD=password
DATABASE_ROOT_PASSWORD=root_password
```
3. Build and run the containers
```bash
make build
make up
# Initialize the database
make migrate
make seed
```
The application will be available at `http://localhost:8080`