ADD auth token for paste creatiog - ref #1
This commit is contained in:
parent
6e9390c197
commit
2a7bab59f3
2 changed files with 104 additions and 18 deletions
22
README.md
22
README.md
|
|
@ -20,6 +20,7 @@
|
||||||
- save and share content via CLI
|
- save and share content via CLI
|
||||||
- up- and download in CLI possible
|
- up- and download in CLI possible
|
||||||
- rate-limits
|
- rate-limits
|
||||||
|
- optional auth token for paste creation
|
||||||
|
|
||||||
**Ideas**:
|
**Ideas**:
|
||||||
- integrated retention/purge function
|
- integrated retention/purge function
|
||||||
|
|
@ -91,6 +92,24 @@ curl -s https://linedump.com/{path} | base64 -d | openssl enc -d -aes-256-cb
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
██ Authentication Examples ██
|
||||||
|
|
||||||
|
If the instance has authentication enabled, include Bearer token:
|
||||||
|
|
||||||
|
█ curl:
|
||||||
|
|
||||||
|
curl -H "Authorization: Bearer YOUR_TOKEN" -X POST -d "Cheers" https://linedump.com/
|
||||||
|
|
||||||
|
█ wget:
|
||||||
|
|
||||||
|
wget --header="Authorization: Bearer YOUR_TOKEN" --post-data="Cheers" -O- https://linedump.com/
|
||||||
|
|
||||||
|
█ Powershell:
|
||||||
|
|
||||||
|
Invoke-RestMethod -Uri "https://linedump.com/" -Headers @{"Authorization"="Bearer YOUR_TOKEN"} -Method Post -Body "Cheers"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
██ Adv Examples ██
|
██ Adv Examples ██
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -148,6 +167,9 @@ podman run --replace -d --restart=unless-stopped \
|
||||||
| `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 |
|
||||||
| `URL_PATH_LENGTH` | Length of generated URL paths (number of characters) | `6` | No |
|
| `URL_PATH_LENGTH` | Length of generated URL paths (number of characters) | `6` | No |
|
||||||
|
| `UPLOAD_TOKENS` | Comma-separated list of Bearer tokens for upload authentication (if set, uploads require valid token) | _(disabled)_ | No |
|
||||||
|
|
||||||
|
Create a secure token with: `openssl rand -base64 32`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
100
main.py
100
main.py
|
|
@ -17,6 +17,7 @@ DESCRIPTION = os.getenv('DESCRIPTION', 'CLI-only pastebin powered by linedump.co
|
||||||
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')
|
||||||
URL_PATH_LENGTH = int(os.getenv('URL_PATH_LENGTH', '6'))
|
URL_PATH_LENGTH = int(os.getenv('URL_PATH_LENGTH', '6'))
|
||||||
|
UPLOAD_TOKENS = [t.strip() for t in os.getenv('UPLOAD_TOKENS', '').split(',') if t.strip()] if os.getenv('UPLOAD_TOKENS') else []
|
||||||
|
|
||||||
limiter = Limiter(key_func=get_remote_address)
|
limiter = Limiter(key_func=get_remote_address)
|
||||||
app = FastAPI(title="linedump", version="1.0.0")
|
app = FastAPI(title="linedump", version="1.0.0")
|
||||||
|
|
@ -42,6 +43,33 @@ def get_client_ip(request: Request) -> str:
|
||||||
return request.client.host
|
return request.client.host
|
||||||
|
|
||||||
|
|
||||||
|
def validate_upload_token(request: Request) -> bool:
|
||||||
|
"""Validate upload token if authentication is enabled"""
|
||||||
|
if not UPLOAD_TOKENS:
|
||||||
|
# No tokens configured, authentication is disabled
|
||||||
|
return True
|
||||||
|
|
||||||
|
auth = request.headers.get("Authorization", "")
|
||||||
|
if not auth.startswith("Bearer "):
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=401,
|
||||||
|
detail="Unauthorized",
|
||||||
|
headers={"WWW-Authenticate": "Bearer"}
|
||||||
|
)
|
||||||
|
|
||||||
|
token = auth[7:] # Remove "Bearer " prefix
|
||||||
|
|
||||||
|
# Use constant-time comparison to prevent timing attacks
|
||||||
|
if not any(secrets.compare_digest(token, valid_token) for valid_token in UPLOAD_TOKENS):
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=401,
|
||||||
|
detail="Unauthorized",
|
||||||
|
headers={"WWW-Authenticate": "Bearer"}
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
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:
|
||||||
|
|
@ -60,7 +88,7 @@ def validate_content(content: str) -> bool:
|
||||||
|
|
||||||
@app.post("/", response_class=PlainTextResponse)
|
@app.post("/", response_class=PlainTextResponse)
|
||||||
@limiter.limit(RATE_LIMIT)
|
@limiter.limit(RATE_LIMIT)
|
||||||
async def upload_text(request: Request):
|
async def upload_text(request: Request, authorized: bool = Depends(validate_upload_token)):
|
||||||
|
|
||||||
body = await request.body()
|
body = await request.body()
|
||||||
content = body.decode('utf-8', errors='ignore')
|
content = body.decode('utf-8', errors='ignore')
|
||||||
|
|
@ -82,8 +110,12 @@ async def upload_text(request: Request):
|
||||||
f.write(content)
|
f.write(content)
|
||||||
|
|
||||||
return f"{BASEURL}/{random_path}\n"
|
return f"{BASEURL}/{random_path}\n"
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
# Log the actual error for debugging
|
||||||
|
import traceback
|
||||||
|
print(f"Error saving file: {e}")
|
||||||
|
print(traceback.format_exc())
|
||||||
raise HTTPException(status_code=500, detail="Failed to save file")
|
raise HTTPException(status_code=500, detail="Failed to save file")
|
||||||
|
|
||||||
@app.get("/{file_path}", response_class=PlainTextResponse)
|
@app.get("/{file_path}", response_class=PlainTextResponse)
|
||||||
|
|
@ -105,6 +137,38 @@ async def get_file(file_path: str):
|
||||||
|
|
||||||
@app.get("/", response_class=PlainTextResponse)
|
@app.get("/", response_class=PlainTextResponse)
|
||||||
async def root():
|
async def root():
|
||||||
|
# Build authentication notice and examples if tokens are configured
|
||||||
|
auth_notice = "\n- Authentication: not required"
|
||||||
|
auth_section = ""
|
||||||
|
auth_header_curl = ""
|
||||||
|
auth_header_wget = ""
|
||||||
|
auth_header_ps = ""
|
||||||
|
|
||||||
|
if UPLOAD_TOKENS:
|
||||||
|
auth_notice = "\n- Authentication: REQUIRED (Bearer token)"
|
||||||
|
auth_header_curl = '-H "Authorization: Bearer $LINEDUMP_TOKEN" '
|
||||||
|
auth_header_wget = '--header="Authorization: Bearer $LINEDUMP_TOKEN" '
|
||||||
|
auth_header_ps = ' -Headers @{"Authorization"="Bearer $env:LINEDUMP_TOKEN"}'
|
||||||
|
auth_section = f"""
|
||||||
|
|
||||||
|
████ Authentication Examples ████
|
||||||
|
|
||||||
|
When authentication is enabled, include Bearer token in Authorization header:
|
||||||
|
|
||||||
|
Set token as environment variable (recommended):
|
||||||
|
export LINEDUMP_TOKEN="your-token-here"
|
||||||
|
|
||||||
|
█ curl:
|
||||||
|
curl -H "Authorization: Bearer $LINEDUMP_TOKEN" -X POST -d "Cheers" {BASEURL}/
|
||||||
|
|
||||||
|
█ wget:
|
||||||
|
wget --header="Authorization: Bearer $LINEDUMP_TOKEN" --post-data="Cheers" -O- {BASEURL}/
|
||||||
|
|
||||||
|
█ Powershell:
|
||||||
|
$env:LINEDUMP_TOKEN="your-token-here"
|
||||||
|
Invoke-RestMethod -Uri "{BASEURL}/" -Headers @{{"Authorization"="Bearer $env:LINEDUMP_TOKEN"}} -Method Post -Body "Cheers"
|
||||||
|
"""
|
||||||
|
|
||||||
return f"""LD {BASEURL}
|
return f"""LD {BASEURL}
|
||||||
|
|
||||||
████ General ████
|
████ General ████
|
||||||
|
|
@ -114,31 +178,31 @@ async def root():
|
||||||
- File limit: {MAX_FILE_SIZE_MB} MB
|
- File limit: {MAX_FILE_SIZE_MB} MB
|
||||||
- Rate limit: {RATE_LIMIT}
|
- Rate limit: {RATE_LIMIT}
|
||||||
- text-only
|
- text-only
|
||||||
- no server-side encryption, consider content public or use client-side encryption
|
- no server-side encryption, consider content public or use client-side encryption{auth_notice}
|
||||||
|
{auth_section}
|
||||||
|
|
||||||
████ Usage ████
|
████ Usage ████
|
||||||
|
|
||||||
|
|
||||||
█ Upload curl:
|
█ Upload curl:
|
||||||
|
|
||||||
curl -X POST -d "Cheers" {BASEURL}/ # string
|
curl {auth_header_curl}-X POST -d "Cheers" {BASEURL}/ # string
|
||||||
curl -X POST {BASEURL} --data-binary @- < file.txt # file
|
curl {auth_header_curl}-X POST {BASEURL} --data-binary @- < file.txt # file
|
||||||
ip -br a | curl -X POST {BASEURL} --data-binary @- # command output
|
ip -br a | curl {auth_header_curl}-X POST {BASEURL} --data-binary @- # command output
|
||||||
|
|
||||||
|
|
||||||
█ Upload wget:
|
█ Upload wget:
|
||||||
|
|
||||||
echo "Cheers" | wget --post-data=@- -O- {BASEURL}/ # string
|
echo "Cheers" | wget {auth_header_wget}--post-data=@- -O- {BASEURL}/ # string
|
||||||
wget --post-file=file.txt -O- {BASEURL}/ # file
|
wget {auth_header_wget}--post-file=file.txt -O- {BASEURL}/ # file
|
||||||
ip -br a | wget --post-data=@- -O- {BASEURL}/ # command output
|
ip -br a | wget {auth_header_wget}--post-data=@- -O- {BASEURL}/ # command output
|
||||||
|
|
||||||
|
|
||||||
█ Upload Powershell:
|
█ Upload Powershell:
|
||||||
|
|
||||||
Invoke-RestMethod -Uri "{BASEURL}/" -Method Post -Body "Cheers" # string
|
Invoke-RestMethod -Uri "{BASEURL}/"{auth_header_ps} -Method Post -Body "Cheers" # string
|
||||||
Invoke-RestMethod -Uri "{BASEURL}/" -Method Post -InFile "file.txt" # file
|
Invoke-RestMethod -Uri "{BASEURL}/"{auth_header_ps} -Method Post -InFile "file.txt" # file
|
||||||
ipconfig | Invoke-RestMethod -Uri "{BASEURL}/" -Method Post -Body {{ $_ }} # command output
|
ipconfig | Invoke-RestMethod -Uri "{BASEURL}/"{auth_header_ps} -Method Post -Body {{ $_ }} # command output
|
||||||
|
|
||||||
|
|
||||||
█ Download:
|
█ Download:
|
||||||
|
|
@ -161,20 +225,20 @@ Invoke-RestMethod -Uri "{BASEURL}/{{path}}" -OutFile "filename.txt" #
|
||||||
|
|
||||||
echo 'Cheers' \
|
echo 'Cheers' \
|
||||||
| openssl enc -aes-256-cbc -pbkdf2 -salt -base64 -pass pass:yourkey \
|
| openssl enc -aes-256-cbc -pbkdf2 -salt -base64 -pass pass:yourkey \
|
||||||
| curl -X POST -d @- {BASEURL}/
|
| curl {auth_header_curl}-X POST -d @- {BASEURL}/
|
||||||
|
|
||||||
|
|
||||||
█ 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 < file.txt \
|
||||||
| curl -sS -X POST {BASEURL} --data-binary @-
|
| curl {auth_header_curl}-sS -X POST {BASEURL} --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 {auth_header_curl}-sS -X POST {BASEURL} --data-binary @-
|
||||||
|
|
||||||
|
|
||||||
█ Download:
|
█ Download:
|
||||||
|
|
@ -193,7 +257,7 @@ curl -s {BASEURL}/{{path}} \
|
||||||
{{ 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 {auth_header_curl}-X POST {BASEURL} --data-binary @-
|
||||||
|
|
||||||
|
|
||||||
█ Continous command:
|
█ Continous command:
|
||||||
|
|
@ -201,7 +265,7 @@ curl -s {BASEURL}/{{path}} \
|
||||||
(timeout --signal=INT --kill-after=5s 10s \\
|
(timeout --signal=INT --kill-after=5s 10s \\
|
||||||
ping 127.1; \\
|
ping 127.1; \\
|
||||||
echo "--- Terminated ---") | \\
|
echo "--- Terminated ---") | \\
|
||||||
curl -X POST --data-binary @- {BASEURL}
|
curl {auth_header_curl}-X POST --data-binary @- {BASEURL}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue