Skip to content

Commit 7afe2d3

Browse files
Maria DrambyanMaria Drambyan
authored andcommitted
Initial commit: Python pastebin application
0 parents  commit 7afe2d3

File tree

8,111 files changed

+2133390
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

8,111 files changed

+2133390
-0
lines changed

.gitignore

Whitespace-only changes.

Dockerfile

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Use Python as base image
2+
FROM python:3.11-slim
3+
4+
# Install system dependencies for database
5+
RUN apt-get update && apt-get install -y \
6+
gcc \
7+
g++ \
8+
&& rm -rf /var/lib/apt/lists/*
9+
10+
# Set working directory
11+
WORKDIR /app
12+
13+
# Copy requirements
14+
COPY requirements.txt ./
15+
16+
# Install dependencies
17+
RUN pip install --no-cache-dir -r requirements.txt
18+
19+
# Copy source code
20+
COPY . .
21+
22+
# Build the frontend
23+
WORKDIR /app/frontend
24+
RUN npm install
25+
RUN npm run build
26+
27+
WORKDIR /app
28+
29+
# Copy built frontend
30+
RUN mkdir -p static && cp -r frontend/dist/* static/
31+
32+
# Initialize database
33+
RUN python -c "
34+
import asyncio
35+
from backend.database import create_tables, get_engine
36+
from backend.models.user import User
37+
from sqlalchemy.ext.asyncio import AsyncSession
38+
import bcrypt
39+
40+
async def init():
41+
engine = get_engine()
42+
await create_tables(engine)
43+
async with AsyncSession(engine) as session:
44+
admin = User(username='admin', password=bcrypt.hashpw(b'admin', bcrypt.gensalt()).decode(), role='admin')
45+
session.add(admin)
46+
await session.commit()
47+
48+
asyncio.run(init())
49+
"
50+
51+
# Expose port
52+
EXPOSE 8000
53+
54+
# Start the server
55+
CMD ["python", "main.py"]

LICENSE

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
Elastic License 2.0
2+
3+
URL: https://www.elastic.co/licensing/elastic-license
4+
5+
## Acceptance
6+
7+
By using the software, you agree to all of the terms and conditions below.
8+
9+
## Copyright License
10+
11+
The licensor grants you a non-exclusive, royalty-free, worldwide,
12+
non-sublicensable, non-transferable license to use, copy, distribute, make
13+
available, and prepare derivative works of the software, in each case subject to
14+
the limitations and conditions below.
15+
16+
## Limitations
17+
18+
You may not provide the software to third parties as a hosted or managed
19+
service, where the service provides users with access to any substantial set of
20+
the features or functionality of the software.
21+
22+
You may not move, change, disable, or circumvent the license key functionality
23+
in the software, and you may not remove or obscure any functionality in the
24+
software that is protected by the license key.
25+
26+
You may not alter, remove, or obscure any licensing, copyright, or other notices
27+
of the licensor in the software. Any use of the licensor's trademarks is subject
28+
to applicable law.
29+
30+
## Patents
31+
32+
The licensor grants you a license, under any patent claims the licensor can
33+
license, or becomes able to license, to make, have made, use, sell, offer for
34+
sale, import and have imported the software, in each case subject to the
35+
limitations and conditions in this license. This license does not cover any
36+
patent claims that you cause to be infringed by modifications or additions to
37+
the software. If you or your company make any written claim that the software
38+
infringes or contributes to infringement of any patent, your patent license for
39+
the software granted under these terms ends immediately. If your company makes
40+
such a claim, your patent license ends immediately for work on behalf of your
41+
company.
42+
43+
## Notices
44+
45+
You must ensure that anyone who gets a copy of any part of the software from you
46+
also gets a copy of these terms.
47+
48+
If you modify the software, you must include in any modified copies of the
49+
software prominent notices stating that you have modified the software.
50+
51+
## No Other Rights
52+
53+
These terms do not imply any licenses other than those expressly granted in
54+
these terms.
55+
56+
## Termination
57+
58+
If you use the software in violation of these terms, such use is not licensed,
59+
and your licenses will automatically terminate. If the licensor provides you
60+
with a notice of your violation, and you cease all violation of this license no
61+
later than 30 days after you receive that notice, your licenses will be
62+
reinstated retroactively. However, if you violate these terms after such
63+
reinstatement, any additional violation of these terms will cause your licenses
64+
to terminate automatically and permanently.
65+
66+
## No Liability
67+
68+
*As far as the law allows, the software comes as is, without any warranty or
69+
condition, and the licensor will not be liable to you for any damages arising
70+
out of these terms or the use or nature of the software, under any kind of
71+
legal claim.*
72+
73+
## Definitions
74+
75+
The **licensor** is the entity offering these terms, and the **software** is the
76+
software the licensor makes available under these terms, including any portion
77+
of it.
78+
79+
**you** refers to the individual or entity agreeing to these terms.
80+
81+
**your company** is any legal entity, sole proprietorship, or other kind of
82+
organization that you work for, plus all organizations that have control over,
83+
are under the control of, or are under common control with that
84+
organization. **control** means ownership of substantially all the assets of an
85+
entity, or the power to direct its management and policies by vote, contract, or
86+
otherwise. Control can be direct or indirect.
87+
88+
**your licenses** are all the licenses granted to you for the software under
89+
these terms.
90+
91+
**use** means anything you do with the software requiring one of your licenses.
92+
93+
**trademark** means trademarks, service marks, and similar rights.

README.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Pastebin Demo Application
2+
3+
A simple Pastebin-like application built with FastAPI, React, TypeScript. This application is intentionally built with minimal security measures for educational purposes in security courses.
4+
5+
## Features
6+
7+
- Code snippet creation and editing
8+
- Support for multiple programming languages:
9+
- TypeScript
10+
- JavaScript
11+
- Python
12+
- Java
13+
- C++
14+
- Syntax highlighting using CodeMirror
15+
- File upload functionality
16+
- Basic user authentication
17+
- Unique URLs for each saved snippet
18+
- SQLite database with SQLAlchemy ORM
19+
20+
## ⚠️ Security Notice
21+
22+
This application is deliberately built WITHOUT security measures for educational purposes. It contains various vulnerabilities including but not limited to:
23+
- SQL Injection possibilities
24+
- No input validation
25+
- Weak authentication
26+
- No CSRF protection
27+
- Potential XSS vulnerabilities
28+
29+
DO NOT USE THIS IN PRODUCTION!
30+
31+
## Prerequisites
32+
33+
- Python 3.9 or higher
34+
- Node.js (v14 or higher)
35+
- npm (Node Package Manager)
36+
37+
## Installation
38+
39+
1. Clone the repository:
40+
```bash
41+
git clone [repository-url]
42+
cd python-pastebin
43+
```
44+
45+
2. Install Python dependencies:
46+
```bash
47+
pip install -r requirements.txt
48+
```
49+
50+
3. Install frontend dependencies:
51+
```bash
52+
cd frontend
53+
npm install
54+
cd ..
55+
```
56+
57+
4. Start the backend and frontend development server:
58+
```bash
59+
python main.py
60+
```
61+
62+
## Usage
63+
64+
1. Access the application at `http://localhost:8000`
65+
66+
2. Login with default credentials:
67+
- Username: `admin`
68+
- Password: `admin`
69+
70+
3. Create new snippets:
71+
- Enter a title
72+
- Select a programming language
73+
- Write or paste your code
74+
- Click "Save" to generate a unique URL
75+
76+
4. Upload files:
77+
- Click the file upload button
78+
- Select a text file
79+
- The content will be automatically loaded into the editor
80+
81+
5. Access saved snippets:
82+
- Use the generated URL (format: `/snippet/:id`)
83+
- Edit and save changes as needed
84+
85+
## API Endpoints
86+
87+
- `POST /api/auth/login` - User authentication
88+
- `POST /api/auth/register` - User registration
89+
- `POST /api/snippets` - Create/update snippets
90+
- `GET /api/snippets/:id` - Retrieve a specific snippet
91+
92+
## Development
93+
94+
Both backend and frontend run on port 8000:
95+
```bash
96+
python main.py
97+
```
98+
99+
## Contributing
100+
101+
This is a demo application for educational purposes. If you find any bugs or want to suggest improvements, please open an issue or submit a pull request.

backend/config.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
API_BASE_URL = '' # Empty string for same-origin requests
2+
JWT_SECRET_KEY = 'jwt-secret-key'
3+
4+
class APIEndpoints:
5+
LOGIN = '/api/auth/login'
6+
REGISTER = '/api/auth/register'
7+
SNIPPETS = '/api/snippets'
8+
9+
@staticmethod
10+
def SNIPPET(id: str):
11+
return f'/api/snippets/{id}'

backend/database.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
2+
from sqlalchemy.orm import sessionmaker, declarative_base
3+
4+
DATABASE_URL = "sqlite+aiosqlite:///./database.sqlite"
5+
6+
engine = create_async_engine(DATABASE_URL)
7+
async_session = sessionmaker(engine, class_=AsyncSession)
8+
Base = declarative_base()
9+
10+
def get_engine():
11+
return engine
12+
13+
async def get_db():
14+
async with async_session() as session:
15+
try:
16+
yield session
17+
finally:
18+
await session.close()
19+
20+
async def create_tables(engine):
21+
async with engine.begin() as conn:
22+
await conn.run_sync(Base.metadata.create_all)

backend/main.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from fastapi import FastAPI, Request
2+
from fastapi.middleware.cors import CORSMiddleware
3+
from fastapi.staticfiles import StaticFiles
4+
from fastapi.responses import FileResponse
5+
from .database import create_tables, get_engine
6+
from .models.user import User, Role
7+
from .database import async_session
8+
from .routes import auth, snippets, admin
9+
import bcrypt
10+
import os
11+
12+
app = FastAPI()
13+
14+
app.add_middleware(
15+
CORSMiddleware,
16+
allow_origins=["*"],
17+
allow_credentials=True,
18+
allow_methods=["*"],
19+
allow_headers=["*"],
20+
)
21+
22+
# Serve static files from the frontend/dist directory
23+
if os.path.exists("frontend/dist"):
24+
app.mount("/assets", StaticFiles(directory="frontend/dist/assets"), name="assets")
25+
26+
@app.on_event("startup")
27+
async def startup_event():
28+
engine = get_engine()
29+
await create_tables(engine)
30+
31+
# Create default admin user
32+
async with async_session() as session:
33+
from sqlalchemy import select
34+
result = await session.execute(select(User).where(User.username == 'admin'))
35+
existing_admin = result.scalar_one_or_none()
36+
37+
if not existing_admin:
38+
hashed_password = bcrypt.hashpw(b'admin', bcrypt.gensalt()).decode('utf-8')
39+
admin = User(username='admin', password=hashed_password, role=Role.ADMIN)
40+
session.add(admin)
41+
await session.commit()
42+
43+
# Include routers
44+
app.include_router(auth.router, prefix="/api/auth")
45+
app.include_router(snippets.router, prefix="/api/snippets")
46+
app.include_router(admin.router, prefix="/api/admin")
47+
48+
# Catch-all route to serve React app
49+
@app.get("/{full_path:path}")
50+
async def serve_react_app(full_path: str):
51+
if full_path.startswith("api/"):
52+
from fastapi import HTTPException
53+
raise HTTPException(status_code=404)
54+
55+
# Serve index.html for client-side routing
56+
if os.path.exists("frontend/dist/index.html"):
57+
return FileResponse("frontend/dist/index.html")
58+
else:
59+
from fastapi import HTTPException
60+
raise HTTPException(status_code=404)

backend/models/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from .user import User
2+
from .snippet import Snippet
3+
4+
__all__ = ['User', 'Snippet']

backend/models/snippet.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from sqlalchemy import Column, String, Text, Integer, ForeignKey
2+
from sqlalchemy.orm import relationship
3+
import uuid
4+
from ..database import Base
5+
6+
class Snippet(Base):
7+
__tablename__ = 'snippets'
8+
9+
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
10+
title = Column(String, nullable=False)
11+
content = Column(Text, nullable=False)
12+
language = Column(String, default='typescript')
13+
userId = Column(Integer, ForeignKey('users.id'), nullable=False)
14+
15+
author = relationship("User", back_populates="snippets")

backend/models/user.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from sqlalchemy import Column, Integer, String, Enum
2+
from sqlalchemy.orm import relationship
3+
from enum import Enum as PyEnum
4+
from ..database import Base
5+
6+
class Role(PyEnum):
7+
USER = "user"
8+
ADMIN = "admin"
9+
10+
class User(Base):
11+
__tablename__ = 'users'
12+
13+
id = Column(Integer, primary_key=True, autoincrement=True)
14+
username = Column(String, unique=True, nullable=False)
15+
password = Column(String, nullable=False)
16+
role = Column(Enum(Role), default=Role.USER)
17+
18+
snippets = relationship("Snippet", back_populates="author")

0 commit comments

Comments
 (0)