Compare commits

..

No commits in common. "main" and "v0.2.1" have entirely different histories.
main ... v0.2.1

2 changed files with 46 additions and 129 deletions

View file

@ -2,9 +2,6 @@
**CLI-only text pastebin service.** **CLI-only text pastebin service.**
[Issue tracker](https://git.uphillsecurity.com/cf7/linedump/issues) | `Libera Chat #linedump`
- Status: Beta - expect minor changes - Status: Beta - expect minor changes
- Instance: [linedump.com](https://linedump.com/) - Instance: [linedump.com](https://linedump.com/)
- Inspired by: - Inspired by:
@ -33,80 +30,7 @@
## Usage ## Usage
```text Check [linedump.com](https://linedump.com) for now - coming soon.
█ Upload curl:
curl -X POST -d "Cheers" https://linedump.com/ # string
curl -X POST https://linedump.com --data-binary @- < file.txt # file
ip -br a | curl -X POST https://linedump.com --data-binary @- # command output
█ Upload wget:
echo "Cheers" | wget --post-data=@- -O- https://linedump.com/ # string
wget --post-file=file.txt -O- https://linedump.com/ # file
ip -br a | wget --post-data=@- -O- https://linedump.com/ # command output
█ Upload Powershell:
Invoke-RestMethod -Uri "https://linedump.com/" -Method Post -Body "Cheers" # string
Invoke-RestMethod -Uri "https://linedump.com/" -Method Post -InFile "file.txt" # file
ipconfig | Invoke-RestMethod -Uri "https://linedump.com/" -Method Post -Body { $_ } # command output
█ Download:
curl https://linedump.com/{path}
wget -O- https://linedump.com/{path}
Invoke-RestMethod -Uri "https://linedump.com/{path}"
██ Encryption Examples with curl ██
█ Upload text:
echo 'Cheers' | openssl enc -aes-256-cbc -salt -pbkdf2 -base64 -pass pass:yourkey | curl -X POST -d @- https://linedump.com/
█ Upload file:
openssl enc -aes-256-cbc -pbkdf2 -salt -pass pass:yourkey -base64 < file.txt | curl -sS -X POST https://linedump.com --data-binary @-
█ Upload command output:
ip -br a | openssl enc -aes-256-cbc -pbkdf2 -salt -pass pass:yourkey -base64 | curl -sS -X POST https://linedump.com --data-binary @-
█ Download:
curl -s https://linedump.com/{path} | base64 -d | openssl enc -d -aes-256-cbc -pbkdf2 -pass pass:yourkey
██ Adv Examples ██
█ Multiple commands:
{ cmd() { printf "\n# %s\n" "$*"; "$@"; }; \
cmd hostname; \
cmd ip -br a; \
} 2>&1 | curl -X POST https://linedump.com --data-binary @-
█ Continous command:
(timeout --signal=INT --kill-after=5s 10s \
ping 127.1; \
echo "--- Terminated ---") | \
curl -X POST --data-binary @- https://linedump.com
```
--- ---
@ -118,7 +42,7 @@ Use with reverse-proxy and HTTPS!
| Variable | Description | Default | Required | | Variable | Description | Default | Required |
|----------|-------------|---------|----------| |----------|-------------|---------|----------|
| `BASEURL` | Base URL used in the application responses and examples | `http://127.0.0.1:8000` | No | | `DOMAIN` | Domain name used in the application responses and examples | `linedump.com` | No |
| `DESCRIPTION` | Application description displayed in the root endpoint | `CLI-only pastebin powered by linedump.com` | No | | `DESCRIPTION` | Application description displayed in the root endpoint | `CLI-only pastebin powered by linedump.com` | No |
| `MAX_FILE_SIZE_MB` | Maximum file size limit in megabytes | `50` | No | | `MAX_FILE_SIZE_MB` | Maximum file size limit in megabytes | `50` | No |
| `RATE_LIMIT` | Rate limit for uploads (format: "requests/timeframe") | `50/hour` | No | | `RATE_LIMIT` | Rate limit for uploads (format: "requests/timeframe") | `50/hour` | No |
@ -132,12 +56,6 @@ For security concerns or reports, please contact via `hello a t uphillsecurity d
--- ---
## Notes
- [Github Mirror available](https://github.com/CaffeineFueled1/linedump)
---
## License ## License
**Apache License** **Apache License**

89
main.py
View file

@ -10,9 +10,11 @@ import os
from pathlib import Path from pathlib import Path
import hashlib import hashlib
from typing import Optional from typing import Optional
from collections import defaultdict
import threading
BASEURL = os.getenv('BASEURL', 'http://127.0.0.1:8000') DOMAIN = os.getenv('DOMAIN', 'linedump.com')
DESCRIPTION = os.getenv('DESCRIPTION', 'CLI-only pastebin powered by linedump.com') DESCRIPTION = os.getenv('DESCRIPTION', 'CLI-only pastebin powered by linedump.com')
MAX_FILE_SIZE_MB = int(os.getenv('MAX_FILE_SIZE_MB', '50')) MAX_FILE_SIZE_MB = int(os.getenv('MAX_FILE_SIZE_MB', '50'))
RATE_LIMIT = os.getenv('RATE_LIMIT', '50/hour') RATE_LIMIT = os.getenv('RATE_LIMIT', '50/hour')
@ -28,6 +30,10 @@ UPLOAD_DIR = Path("uploads")
UPLOAD_DIR.mkdir(exist_ok=True) UPLOAD_DIR.mkdir(exist_ok=True)
MAX_FILE_SIZE = MAX_FILE_SIZE_MB * 1024 * 1024 # Convert MB to bytes MAX_FILE_SIZE = MAX_FILE_SIZE_MB * 1024 * 1024 # Convert MB to bytes
MAX_FILES_PER_IP = 100
file_counter = defaultdict(int)
lock = threading.Lock()
def generate_random_path(length: int = None) -> str: def generate_random_path(length: int = None) -> str:
if length is None: if length is None:
@ -42,6 +48,11 @@ def get_client_ip(request: Request) -> str:
return request.client.host return request.client.host
def check_file_limit(request: Request) -> bool:
client_ip = get_client_ip(request)
with lock:
return file_counter[client_ip] < MAX_FILES_PER_IP
def validate_content(content: str) -> bool: def validate_content(content: str) -> bool:
"""Basic validation for content size and encoding""" """Basic validation for content size and encoding"""
if len(content) > MAX_FILE_SIZE: if len(content) > MAX_FILE_SIZE:
@ -62,6 +73,9 @@ def validate_content(content: str) -> bool:
@limiter.limit(RATE_LIMIT) @limiter.limit(RATE_LIMIT)
async def upload_text(request: Request): async def upload_text(request: Request):
if not check_file_limit(request):
raise HTTPException(status_code=429, detail="File limit exceeded")
body = await request.body() body = await request.body()
content = body.decode('utf-8', errors='ignore') content = body.decode('utf-8', errors='ignore')
@ -80,8 +94,13 @@ async def upload_text(request: Request):
try: try:
with open(file_path, 'w', encoding='utf-8') as f: with open(file_path, 'w', encoding='utf-8') as f:
f.write(content) f.write(content)
return f"{BASEURL}/{random_path}\n" client_ip = get_client_ip(request)
with lock:
file_counter[client_ip] += 1
base_url = f"https://{request.headers.get('host', request.url.netloc)}"
return f"{base_url}/{random_path}\n"
except Exception as e: except Exception as e:
raise HTTPException(status_code=500, detail="Failed to save file") raise HTTPException(status_code=500, detail="Failed to save file")
@ -105,7 +124,7 @@ async def get_file(file_path: str):
@app.get("/", response_class=PlainTextResponse) @app.get("/", response_class=PlainTextResponse)
async def root(): async def root():
return f"""LD {BASEURL} return f"""C|_| {DOMAIN}
General General
@ -122,32 +141,32 @@ async def root():
Upload curl: Upload curl:
curl -X POST -d "Cheers" {BASEURL}/ # string curl -X POST -d "Cheers" https://{DOMAIN}/ # string
curl -X POST {BASEURL} --data-binary @- < file.txt # file curl -X POST https://{DOMAIN} --data-binary @- < file.txt # file
ip -br a | curl -X POST {BASEURL} --data-binary @- # command output ip -br a | curl -X POST https://{DOMAIN} --data-binary @- # command output
Upload wget: Upload wget:
echo "Cheers" | wget --post-data=@- -O- {BASEURL}/ # string echo "Cheers" | wget --post-data=@- -O- https://{DOMAIN}/ # string
wget --post-file=file.txt -O- {BASEURL}/ # file wget --post-file=file.txt -O- https://{DOMAIN}/ # file
ip -br a | wget --post-data=@- -O- {BASEURL}/ # command output ip -br a | wget --post-data=@- -O- https://{DOMAIN}/ # command output
Upload Powershell: Upload Powershell:
Invoke-RestMethod -Uri "{BASEURL}/" -Method Post -Body "Cheers" # string Invoke-RestMethod -Uri "https://{DOMAIN}/" -Method Post -Body "Cheers" # string
Invoke-RestMethod -Uri "{BASEURL}/" -Method Post -InFile "file.txt" # file Invoke-RestMethod -Uri "https://{DOMAIN}/" -Method Post -InFile "file.txt" # file
ipconfig | Invoke-RestMethod -Uri "{BASEURL}/" -Method Post -Body {{ $_ }} # command output ipconfig | Invoke-RestMethod -Uri "https://{DOMAIN}/" -Method Post -Body {{ $_ }} # command output
Download: Download:
curl {BASEURL}/{{path}} curl https://{DOMAIN}/{{path}}
wget -O- {BASEURL}/{{path}} wget -O- https://{DOMAIN}/{{path}}
Invoke-RestMethod -Uri "{BASEURL}/{{path}}" Invoke-RestMethod -Uri "https://{DOMAIN}/{{path}}"
@ -157,26 +176,23 @@ Invoke-RestMethod -Uri "{BASEURL}/{{path}}"
Upload text: Upload text:
echo 'Cheers' \ echo 'Cheers' \
| openssl enc -aes-256-cbc -pbkdf2 -salt -base64 -pass pass:yourkey \ | openssl enc -aes-256-cbc -pbkdf2 -base64 -pass pass:yourkey \
| curl -X POST -d @- {BASEURL}/ | curl -X POST -d @- https://{DOMAIN}/
Upload file: Upload file:
openssl enc -aes-256-cbc -pbkdf2 -salt -pass pass:yourkey -base64 < file.txt \ openssl enc -aes-256-cbc -pbkdf2 -salt -pass pass:yourkey -base64 < YOURFILE.txt \
| curl -sS -X POST {BASEURL} --data-binary @- | curl -sS -X POST https://{DOMAIN} --data-binary @-
Upload command output: Upload command output:
ip -br a \ ip -br a \
| openssl enc -aes-256-cbc -pbkdf2 -salt -pass pass:yourkey -base64 \ | openssl enc -aes-256-cbc -pbkdf2 -salt -pass pass:yourkey -base64 \
| curl -sS -X POST {BASEURL} --data-binary @- | curl -sS -X POST https://{DOMAIN} --data-binary @-
Download: Download:
curl -s {BASEURL}/{{path}} \ curl -s https://{DOMAIN}/PASTE_THE_ID \
| base64 -d \ | base64 -d \
| openssl enc -d -aes-256-cbc -pbkdf2 -pass pass:yourkey | openssl enc -d -aes-256-cbc -pbkdf2 -pass pass:yourkey
@ -185,35 +201,18 @@ curl -s {BASEURL}/{{path}} \
Adv Examples Adv Examples
Multiple commands: Multiple Commands
{{ cmd() {{ printf "\\n# %s\\n" "$*"; "$@"; }}; \\ {{ cmd() {{ printf "\\n# %s\\n" "$*"; "$@"; }}; \\
cmd hostname; \\ cmd hostname; \\
cmd ip -br a; \\ cmd ip -br a; \\
}} 2>&1 | curl -X POST {BASEURL} --data-binary @- }} 2>&1 | curl -X POST https://{DOMAIN} --data-binary @-
Continous command:
(timeout --signal=INT --kill-after=5s 10s \\
ping 127.1; \\
echo "--- Terminated ---") | \\
curl -X POST --data-binary @- {BASEURL}
Further Information Further Information
Powered by linedump More information will follow. Work in Progress.
Source:
https://git.uphillsecurity.com/cf7/linedump
License:
Apache-2.0
https://git.uphillsecurity.com/cf7/linedump/src/branch/main/LICENSE
""" """
if __name__ == "__main__": if __name__ == "__main__":