5 Commits

Author SHA1 Message Date
Tyler 8f2d56c05a Better UI for both Desktop and Mobile 2025-05-14 15:31:43 -10:00
Tyler bb8690b74f UI Changes and better phone experience. 2025-05-14 05:00:12 -10:00
Tyler ed11ccd2a1 Update README.md 2025-05-04 13:30:40 -10:00
Tyler db00538aee Small changed
Updated README and Logo Change
2025-05-04 13:29:08 -10:00
Tyler 05a9ada8d9 Update README.md 2025-05-01 21:58:23 -10:00
20 changed files with 1003 additions and 624 deletions
+113 -22
View File
@@ -1,9 +1,9 @@
# PacCrypt WebApp # PacCrypt
**PacCrypt** is a secure, feature-rich web app for encrypting and decrypting text and files — built with Flask, JavaScript, and AES-GCM encryption. **PacCrypt** is a secure, feature-rich web app for encrypting and decrypting text and files — built with Flask, JavaScript, and AES-GCM encryption.
Now with an admin control panel, GitHub updater, and a built-in Pac-Man easter egg! 🕹️ Now with an admin control panel, GitHub updater, and a built-in Pac-Man easter egg! 🕹️
Live demo: [paccrypt.unnaturalll.dev](http://paccrypt.unnaturalll.dev) Officially Hosted Here: [paccrypt.unnaturalll.dev](http://paccrypt.unnaturalll.dev)
--- ---
@@ -35,8 +35,9 @@ Live demo: [paccrypt.unnaturalll.dev](http://paccrypt.unnaturalll.dev)
- Flask 3+ - Flask 3+
- Cryptography 42+ - Cryptography 42+
- Waitress 2.1+ - Waitress 2.1+
- Git (for update feature) - Git (For update feature)
- Nginx (recommended) - Nginx (Recommended)
- Cockpit (Recommended if hosted on **Linux**)
--- ---
@@ -54,45 +55,49 @@ Then run:
- Development Mode: - Development Mode:
```bash ```bash
./start_dev.sh # or start_dev.bat ./start_dev.sh #<-- start_dev.bat (Windows)
``` ```
- Production Mode: - Production Mode:
```bash ```bash
./start_prod.sh # or start_prod.bat ./start_prod.sh #<-- start_prod.bat (Windows)
``` ```
Visit [http://127.0.0.1:5000](http://127.0.0.1:5000) Visit [http://127.0.0.1:5000](http://127.0.0.1:5000) or [http://localhost:5000](http://localhost:5000) - *If* you **are** on the host system
Visit http://hosts_private_ip - *If* you are **not** on the host system
--- ---
## 🧭 Navigation & Usage ## 🧭 Navigation & Usage
### 🔑 Generate Passwords
- Click Generate
- Then hit `📋 Copy Password`
- **Note:** This is also used as a seed generator for the Pac-Man *like* game
### 🔐 Encrypt & Decrypt ### 🔐 Encrypt & Decrypt
- Choose between Basic Cipher or Advanced AES - Choose between Basic Cipher or Advanced AES
- Type your message or upload a file
- Enter password (if AES)
- Select mode using toggle (Encrypt/Decrypt) - Select mode using toggle (Encrypt/Decrypt)
- Type your message or upload a file
- Enter password (Advanced AES)
- Hit Execute - Hit Execute
- Then hit `📋 Copy Output`
### 📤 Share Files ### 📤 Share Files
- Upload a file with two passwords: - Upload a file with two passwords:
- Encryption password - Encryption password
- Pickup password - Pickup password
- Get a shareable URL and click 📋 Copy Link - Get a shareable URL and click `📋 Copy Link`
### 🔑 Generate Passwords ### 🎮 Pac-Man *like* Game
- Click Generate
- Then hit 📋 Copy
### 🎮 Pac-Man Game
- Type `pacman` in the input box - Type `pacman` in the input box
- Game appears with Restart/Exit controls - Game appears with `Restart` and `Exit` buttons
- Classic arrow key controls 🕹️ - Arrow key and Swipe controls 🕹️
- Game restarts and a new seed is generated once all dots are eaten
--- ---
@@ -111,31 +116,117 @@ Features:
--- ---
## 🛡️ Deployment Tips ## 🛡️ Deployment Tips
##### I recommend using Linux as the host server, the follow confs are Linux focused
The official PacCrypt host is **Debian** minimal install.
Minimal Nginx config: **HTTP** Nginx config (Not recommended):
```nginx ```nginx
server { server {
listen 80; listen 80;
server_name yourdomain.com; server_name yourdomain.com; #<-- Your URL here
# Basic Privacy-Respecting Logging
access_log off; #<-- set to syslog:server=unix:/dev/log; for logging
error_log syslog:server=unix:/dev/log crit; #<-- Currently set for only critical logs, remove crit for all logs
# Hardened Proxy Settings
location / { location / {
proxy_pass http://127.0.0.1:5000; proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Connection "";
# Timeouts
proxy_connect_timeout 5s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
} }
# Basic Hardening Headers
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer" always;
add_header Permissions-Policy "geolocation=(), microphone=()" always;
# Prevent Abuse
client_max_body_size 10M;
keepalive_timeout 10;
server_tokens off;
} }
``` ```
Use Let's Encrypt to add SSL/TLS support. **HTTPS** Nginx config (Recommended):
```nginx
# Redirect HTTP to HTTPS
server {
listen 80;
server_name yourdomain.com; #<-- Your URL here
# Basic Privacy-Respecting Logging
access_log off; #<-- set to syslog:server=unix:/dev/log; for logging
error_log syslog:server=unix:/dev/log crit; #<-- Currently set for only critical logs, remove crit for all logs
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS Server Block
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate path/to/yourdomain.com.cert; #<-- Could also be .cert.pem
ssl_certificate_key path/to/yourdomain.com.key; #<-- Could also be .key.pem
# SSL Hardening
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Strong security headers (adjust as needed)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
add_header Referrer-Policy "no-referrer" always;
add_header Permissions-Policy "geolocation=(), camera=()" always;
add_header X-XSS-Protection "1; mode=block" always;
# Basic Privacy-Respecting Logging
access_log off; #<-- set to syslog:server=unix:/dev/log; for logging
error_log syslog:server=unix:/dev/log crit; #<-- Currently set for only critical logs, remove crit for all logs
client_max_body_size xG; #<-- Change to what the max upload for PacCrypt Share
# Reverse proxy to Flask
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
# Comment these out if you want complete anonymity between client and app
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto $scheme;
# Optional privacy: strip identifying headers
proxy_hide_header X-Powered-By;
}
}
```
--- ---
## 🗂️ Project Structure ## 🗂️ Project Structure
``` ```
paccrypt-webapp-final/ PacCrypt/
├── app.py ├── app.py
├── requirements.txt ├── requirements.txt
├── README.md ├── README.md
+35 -58
View File
@@ -6,11 +6,11 @@ import html
import base64 import base64
import hashlib import hashlib
import secrets import secrets
import datetime
import subprocess import subprocess
import platform import platform
from datetime import UTC from datetime import datetime, timedelta
import sys import sys
import psutil
# ===== Third-Party Imports ===== # ===== Third-Party Imports =====
from flask import ( from flask import (
@@ -138,7 +138,7 @@ def log_admin_event(message: str):
try: try:
key = load_admin_key() key = load_admin_key()
cipher = Fernet(key) cipher = Fernet(key)
timestamp = datetime.datetime.now(UTC).strftime("%Y-%m-%d %H:%M:%S") timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
encrypted = cipher.encrypt(f"[{timestamp}] {message}".encode()) encrypted = cipher.encrypt(f"[{timestamp}] {message}".encode())
with open(ADMIN_LOG_FILE, 'ab') as f: with open(ADMIN_LOG_FILE, 'ab') as f:
f.write(encrypted + b"\n") f.write(encrypted + b"\n")
@@ -149,12 +149,12 @@ def log_admin_event(message: str):
def cleanup_expired_files(): def cleanup_expired_files():
"""Remove files older than MAX_FILE_AGE_DAYS.""" """Remove files older than MAX_FILE_AGE_DAYS."""
try: try:
now = datetime.datetime.now(UTC) now = datetime.now()
for fname in os.listdir(UPLOAD_FOLDER): for fname in os.listdir(UPLOAD_FOLDER):
if fname.endswith(".enc") or fname.endswith(".json"): if fname.endswith(".enc") or fname.endswith(".json"):
path = os.path.join(UPLOAD_FOLDER, fname) path = os.path.join(UPLOAD_FOLDER, fname)
try: try:
file_time = datetime.datetime.fromtimestamp(os.path.getmtime(path), UTC) file_time = datetime.datetime.fromtimestamp(os.path.getmtime(path), )
age = (now - file_time).days age = (now - file_time).days
if age > MAX_FILE_AGE_DAYS: if age > MAX_FILE_AGE_DAYS:
os.remove(path) os.remove(path)
@@ -208,7 +208,7 @@ def handle_file_upload(request):
meta = { meta = {
'pickup_password': base64.urlsafe_b64encode(hashlib.sha256(pickup_password.encode()).digest()).decode(), 'pickup_password': base64.urlsafe_b64encode(hashlib.sha256(pickup_password.encode()).digest()).decode(),
'original_name': filename, 'original_name': filename,
'timestamp': datetime.datetime.now(UTC).isoformat() 'timestamp': datetime.datetime.now().isoformat()
} }
with open(os.path.join(UPLOAD_FOLDER, f"{random_id}.json"), 'w') as f: with open(os.path.join(UPLOAD_FOLDER, f"{random_id}.json"), 'w') as f:
json.dump(meta, f) json.dump(meta, f)
@@ -408,48 +408,30 @@ def admin_page():
cleanup_expired_files() cleanup_expired_files()
routes = [rule.rule for rule in app.url_map.iter_rules() if rule.endpoint != 'static'] routes = [rule.rule for rule in app.url_map.iter_rules() if rule.endpoint != 'static']
# Get uptime based on OS now = datetime.now()
if platform.system() == "Windows": try:
try: boot_time = datetime.fromtimestamp(psutil.boot_time())
# Windows uptime using PowerShell
ps_command = "(Get-CimInstance -ClassName Win32_OperatingSystem).LastBootUpTime" uptime = now - boot_time
uptime_output = subprocess.check_output(["powershell", "-Command", ps_command], shell=True).decode() days = uptime.days
# Convert the PowerShell DateTime to Python datetime hours, remainder = divmod(uptime.seconds, 3600)
boot_time = datetime.datetime.strptime(uptime_output.strip(), "%A, %B %d, %Y %I:%M:%S %p") minutes = remainder // 60
# Make boot_time timezone-aware (assuming local time) uptime_str = f"{days} days, {hours} hours, {minutes} minutes"
boot_time = boot_time.replace(tzinfo=datetime.timezone.utc) except Exception as e:
current_time = datetime.datetime.now(UTC) print(f"[ERROR] Uptime calculation failed: {e}")
uptime = current_time - boot_time uptime_str = "Unavailable"
uptime_str = f"{uptime.days} days, {uptime.seconds // 3600} hours, {(uptime.seconds % 3600) // 60} minutes"
except Exception as e:
print(f"[ERROR] Failed to get Windows uptime: {str(e)}")
uptime_str = "Unavailable"
else:
try:
# Try reading from /proc/uptime first
with open('/proc/uptime', 'r') as f:
uptime_seconds = float(f.readline().split()[0])
days = int(uptime_seconds // 86400)
hours = int((uptime_seconds % 86400) // 3600)
minutes = int((uptime_seconds % 3600) // 60)
uptime_str = f"{days} days, {hours} hours, {minutes} minutes"
except Exception:
try:
# Fallback to uptime command if /proc/uptime fails
uptime_str = subprocess.check_output("uptime -p", shell=True).decode().strip()
except Exception as e:
print(f"[ERROR] Failed to get Linux uptime: {str(e)}")
uptime_str = "Unavailable"
server_info = { server_info = {
"uptime": uptime_str, "uptime": uptime_str,
"time": datetime.datetime.now(UTC).strftime("%Y-%m-%d %H:%M:%S"), "server_time": now.strftime("%Y-%m-%d %H:%M:%S"),
"python": platform.python_version(), "python_version": platform.python_version(),
"debug": app.debug "debug_mode": app.debug
} }
return render_template("admin.html", routes=routes, server_info=server_info) return render_template("admin.html", routes=routes, server_info=server_info)
@app.route("/restart-server", methods=["POST"]) @app.route("/restart-server", methods=["POST"])
def restart_server(): def restart_server():
"""Restart the server.""" """Restart the server."""
@@ -458,9 +440,7 @@ def restart_server():
try: try:
if platform.system() == "Windows": if platform.system() == "Windows":
# Get the current process ID
current_pid = os.getpid() current_pid = os.getpid()
# Create a batch file to restart the server
restart_script = f""" restart_script = f"""
@echo off @echo off
timeout /t 2 /nobreak timeout /t 2 /nobreak
@@ -470,33 +450,30 @@ def restart_server():
""" """
with open("restart.bat", "w") as f: with open("restart.bat", "w") as f:
f.write(restart_script) f.write(restart_script)
# Start the restart script and exit
subprocess.Popen(["restart.bat"], shell=True) subprocess.Popen(["restart.bat"], shell=True)
return jsonify({"message": "Server restart initiated"}), 200 return jsonify({"message": "Server restart initiated"}), 200
else: else:
# For Linux/Unix systems, use a Python-based restart current_pid = os.getpid()
# Get the current Python interpreter and script path
python_path = sys.executable python_path = sys.executable
script_path = os.path.abspath(__file__) script_path = os.path.abspath(__file__)
current_pid = os.getpid()
# Create a shell script to restart the server # Create a safer and cleaner restart script
restart_script = f"""#!/bin/bash restart_script = """#!/bin/bash
sleep 2 sleep 2
kill -9 {current_pid} PID=$1
export PRODUCTION=true kill "$PID"
{python_path} {script_path} while kill -0 "$PID" 2>/dev/null; do sleep 0.5; done
""" export PRODUCTION=true
exec "$2" "$3"
"""
# Write and make the script executable
with open("restart.sh", "w") as f: with open("restart.sh", "w") as f:
f.write(restart_script) f.write(restart_script)
os.chmod("restart.sh", 0o755) os.chmod("restart.sh", 0o755)
# Start the restart script and exit subprocess.Popen(["./restart.sh", str(current_pid), python_path, script_path])
subprocess.Popen(["./restart.sh"], shell=True)
return jsonify({"message": "Server restart initiated"}), 200 return jsonify({"message": "Server restart initiated"}), 200
except Exception as e: except Exception as e:
print(f"[ERROR] Failed to restart server: {str(e)}") print(f"[ERROR] Failed to restart server: {str(e)}")
return jsonify({"error": f"Failed to restart server: {str(e)}"}), 500 return jsonify({"error": f"Failed to restart server: {str(e)}"}), 500
+1
View File
@@ -4,6 +4,7 @@ flask==3.0.3
cryptography==42.0.5 cryptography==42.0.5
waitress==2.1.2 waitress==2.1.2
werkzeug==3.0.1 werkzeug==3.0.1
psutil>=5.9.0,<6.0.0
# nginx - Only needed for Nginx integration, not installed via pip # nginx - Only needed for Nginx integration, not installed via pip
# Run pip install -r requirements.txt # Run pip install -r requirements.txt
+7
View File
@@ -0,0 +1,7 @@
@echo off
timeout /t 2 /nobreak
taskkill /F /PID 15428
set PRODUCTION=true
start "" "python" "app.py"
+17
View File
@@ -0,0 +1,17 @@
#!/bin/bash
sleep 2
# Save current process PID
PID=$1
# Gracefully stop the current server
kill "$PID"
# Wait until it exits
while kill -0 "$PID" 2>/dev/null; do
sleep 0.5
done
# Restart with the same interpreter and script
export PRODUCTION=true
exec "$2" "$3"
+306 -112
View File
@@ -1,15 +1,17 @@
/* ===== Global Reset ===== */ /* ===== Global Reset ===== */
* { * {
box-sizing: border-box; box-sizing: border-box;
margin: 3px; gap: 6px !important;
padding: 0; padding: 0;
} }
/* ===== Body ===== */ /* ===== Body ===== */
body { body {
font-family: 'Poppins', sans-serif; font-family: 'Press Start 2P', monospace;
background-color: #121212; background-color: #0e0e0e;
color: #00ff99; color: #28E060;
font-size: 13px;
line-height: 1.6;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 100vh; min-height: 100vh;
@@ -18,27 +20,137 @@ body {
padding: 20px; padding: 20px;
} }
/* ===== Header ===== */ @media (max-width: 600px) {
header { #sitemap-section,
text-align: center; #password-change-section,
padding: 25px; #server-update-section,
background-color: #1c1c1c; #server-status-section,
border-radius: 12px; #server-logs-section,
box-shadow: 0 0 15px rgba(0, 255, 153, 0.4); #system-settings-section {
width: 100%; padding: 20px;
max-width: 800px; margin-bottom: 20px;
margin-bottom: 40px !important; }
#sitemap-section li,
#server-status-section li {
font-size: 0.9em;
padding: 6px;
}
#logContainer {
font-size: 0.9em;
padding: 10px;
}
body {
font-size: 11px;
padding: 10px;
}
.button-group,
.admin-button-grid {
flex-direction: column;
align-items: center;
}
.button-group button,
.admin-button-grid button {
min-width: 75%;
max-width: 75%;
}
header {
flex-direction: column;
height: auto;
padding-inline: 15px;
padding-block: 20px;
}
.logo-container {
flex-direction: column;
align-items: center;
}
.logo-container img {
height: 100px !important;
margin-top: -15px !important;
}
.logo-text {
margin-left: 0 !important;
text-align: center;
}
.logo-text h1 {
font-size: 1.4em;
margin-top: -30px !important;
margin-left: 0 !important;
text-align: center !important;
}
.logo-text p {
font-size: 0.8em;
margin-left: 0 !important;
text-align: center !important;
}
.admin-button-grid {
grid-template-columns: 1fr;
}
.status-list {
width: 100%;
max-width: 400px;
padding-left: 0;
list-style: none;
word-wrap: break-word;
overflow-wrap: break-word;
}
} }
header h1 { /* ===== Header ===== */
font-size: 2.8em; header {
color: #00ff99; display: flex;
margin-bottom: 8px; justify-content: center;
} align-items: center;
background-color: #111;
border-radius: 12px;
box-shadow: 0 0 15px #28E060;
width: 100%;
max-width: 800px;
margin-bottom: 25px;
padding: 25px;
height: 200px;
}
.logo-container {
display: flex;
align-items: center;
}
.logo-container img {
height: 200px;
width: auto;
}
.logo-text h1 {
font-size: clamp(1.4em, 6vw, 2.8em);
word-break: break-word;
overflow-wrap: break-word;
color: #28E060;
margin: 0;
margin-left: -30px; /* overlap effect */
text-align: left;
}
.logo-text p {
font-size: 1.2em;
color: #28E060;
margin: 0;
margin-left: -30px;
text-align: left;
}
header p {
font-size: 1.2em;
}
/* ===== Main Layout ===== */ /* ===== Main Layout ===== */
main { main {
@@ -49,7 +161,6 @@ main {
width: 100%; width: 100%;
max-width: 800px; max-width: 800px;
padding: 0; padding: 0;
gap: 0;
} }
/* ===== Card Styling ===== */ /* ===== Card Styling ===== */
@@ -58,7 +169,7 @@ main {
padding: 25px; padding: 25px;
width: 100%; width: 100%;
border-radius: 12px; border-radius: 12px;
box-shadow: 0 0 15px rgba(0, 255, 153, 0.4); box-shadow: 0 0 15px #28E060;
text-align: center; text-align: center;
} }
@@ -67,26 +178,46 @@ main {
display: flex !important; display: flex !important;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 0px;
max-width: 725px; max-width: 725px;
width: 100%; width: 100%;
} }
.status-list {
width: 100%;
max-width: 400px;
padding-left: 0;
list-style: none;
word-wrap: break-word;
overflow-wrap: break-word;
}
/* ===== Inputs, Textareas, Selects ===== */ /* ===== Inputs, Textareas, Selects ===== */
button,
select,
input,
textarea {
font-family: 'Press Start 2P', monospace;
font-size: 12px !important;
letter-spacing: 0.5px;
}
input, input,
textarea, textarea,
select, select,
input[type="file"] { input[type="file"] {
width: 80%; width: 80%;
max-width: 500px; max-width: 500px;
padding: 12px 20px; padding-inline: 20px;
border: 1px solid #00ff99; padding-block: 12px;
border: 1px solid #28E060;
border-radius: 8px; border-radius: 8px;
background-color: #2c2f33; background-color: #2c2f33;
color: #00ff99; color: #28E060;
font-size: 1em;
text-align: left; text-align: left;
transition: 0.3s; transition: 0.3s;
min-height: 50px;
} }
select { select {
@@ -98,35 +229,41 @@ textarea {
resize: none; resize: none;
} }
input[type="password"] { /* ===== File Input Customization ===== */
min-height: 50px;
}
input[type="file"] { input[type="file"] {
border: 2px dashed #00ff99; border: 2px dashed #28E060;
cursor: pointer; cursor: pointer;
color: #28E060;
background-color: #2c2f33;
} }
input[type="file"]::file-selector-button { input[type="file"]::file-selector-button {
background-color: #00ff99; font-family: 'Press Start 2P', monospace;
color: #121212; font-size: 12px;
border: none; background-color: #2c2f33;
padding: 8px 15px; color: #28E060;
border-radius: 6px; border: 2px solid #28E060;
cursor: pointer; padding-inline: 10px;
transition: 0.3s; padding-block: 8px;
} margin-right: 10px;
border-radius: 6px;
text-transform: uppercase;
cursor: pointer;
transition: 0.3s ease;
}
input[type="file"]::file-selector-button:hover { input[type="file"]::file-selector-button:hover {
background-color: #00cc77; background-color: #28E060;
} color: #000;
box-shadow: 0 0 10px #28E060;
}
/* ===== Focus Effects ===== */ /* ===== Focus Effects ===== */
input:focus, input:focus,
textarea:focus, textarea:focus,
select:focus { select:focus {
outline: none; outline: none;
box-shadow: 0 0 10px rgba(0, 255, 153, 0.8); box-shadow: 0 0 10px #28E060;
} }
/* ===== Textareas Specific Widths ===== */ /* ===== Textareas Specific Widths ===== */
@@ -142,47 +279,132 @@ select:focus {
display: flex; display: flex;
flex-wrap: nowrap; flex-wrap: nowrap;
justify-content: center; justify-content: center;
gap: 15px;
width: 100%; width: 100%;
} }
button { button {
padding: 10px 20px; padding-inline: 20px;
border: 0px solid #00ff99; padding-block: 10px;
border: none;
border-radius: 8px; border-radius: 8px;
background-color: #2c2f33; background-color: #2c2f33;
color: #00ff99; color: #28E060;
font-size: 1em; font-size: 1em;
cursor: pointer; cursor: pointer;
transition: 0.3s; transition: 0.3s;
width: auto; width: auto;
min-width: 225px; min-width: 225px;
max-width: 300px; max-width: 300px;
height: 45px;
} }
button:hover { button:hover {
background-color: #00ff99; background-color: #28E060;
color: #121212; color: #121212;
box-shadow: 0 0 10px rgba(0, 255, 153, 0.4); box-shadow: 0 0 10px #28E060;
} }
.danger-button { .danger-button {
background-color: #5f3131; background-color: #5f3131;
box-shadow: 0 0 20px rgba(185, 0, 0, 0.4); box-shadow: 0 0 10px #991717;
} }
.danger-button:hover { .danger-button:hover {
background-color: #ff0000; background-color: #af0000;
color: #121212; color: #121212;
box-shadow: 0 0 40px rgb(255, 0, 0); box-shadow: 0 0 40px #ff0000;
} }
.admin-button-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
justify-items: center;
width: 100%;
max-width: 640px;
margin: 0 auto;
}
.admin-button-grid button {
width: 100%;
max-width: 280px;
font-family: 'Press Start 2P', monospace;
font-size: 12px;
}
/* ===== Toggle Switch Styling ===== */ /* ===== Toggle Switch Styling ===== */
.toggle-container { .toggle-container {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 12px; }
.toggle-label {
font-family: 'Press Start 2P', monospace;
font-size: 12px;
color: #28E060;
}
.material-switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}
.material-switch input {
opacity: 0;
width: 0;
height: 0;
}
.material-slider {
position: absolute;
cursor: pointer;
top: 0; left: 0; right: 0; bottom: 0;
background-color: #222;
border: 2px solid #28E060;
border-radius: 34px;
transition: 0.4s;
margin: unset;
}
.material-slider::before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 2px;
bottom: 2px;
background-color: #28E060;
border-radius: 50%;
transition: 0.4s;
box-shadow: 0 0 6px #28E060;
}
.material-switch input:checked + .material-slider {
background-color: #28E060;
}
.material-switch input:checked + .material-slider::before {
transform: translateX(26px);
background-color: #000;
}
/* Label beside switch */
#toggle-label {
font-family: 'Press Start 2P', monospace;
color: #28E060;
margin-left: 20px;
font-size: 12px;
}
.toggle-container {
display: flex;
align-items: center;
justify-content: center;
width: 100%; width: 100%;
} }
@@ -211,7 +433,7 @@ button {
right: 0; right: 0;
bottom: 0; bottom: 0;
background-color: #2c2f33; background-color: #2c2f33;
border: 2px solid #00ff99; border: 2px solid #28E060;
border-radius: 34px; border-radius: 34px;
transition: .4s; transition: .4s;
display: flex; display: flex;
@@ -223,7 +445,7 @@ button {
content: ""; content: "";
height: 22px; height: 22px;
width: 22px; width: 22px;
background-color: #00ff99; background-color: #28E060;
border-radius: 50%; border-radius: 50%;
transition: .4s; transition: .4s;
transform: translateX(2px); transform: translateX(2px);
@@ -243,7 +465,7 @@ input:checked + .slider::before {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
font-size: 0.9em; font-size: 0.9em;
color: #00ff99; color: #28E060;
margin-top: 5px; margin-top: 5px;
} }
@@ -265,7 +487,7 @@ input:checked + .slider::before {
max-width: 500px; max-width: 500px;
min-height: 50px; min-height: 50px;
background-color: #333; background-color: #333;
color: #00ff99; color: #28E060;
text-align: center; text-align: center;
border-radius: 8px; border-radius: 8px;
padding: 14px; padding: 14px;
@@ -306,16 +528,16 @@ footer {
text-align: center; text-align: center;
padding: 25px; padding: 25px;
background-color: #1c1c1c; background-color: #1c1c1c;
color: #00ff99; color: #28E060;
border-radius: 12px; border-radius: 12px;
box-shadow: 0 0 15px rgba(0, 255, 153, 0.4); box-shadow: 0 0 15px #28E060;
width: 100%; width: 100%;
max-width: 800px; max-width: 800px;
margin-top: 40px; margin-top: 25px;
} }
footer a { footer a {
color: #00ff99; color: #28E060;
text-decoration: none; text-decoration: none;
} }
@@ -330,18 +552,19 @@ footer {
select, select,
#input-text, #input-text,
#output-text { #output-text {
width: 100%; width: 100% !important;
max-width: 90%; max-width: 90% !important;
} }
} }
/* ===== Copy Feedback Message ===== */ /* ===== Copy Feedback Message ===== */
.copy-feedback, #shared-link-feedback { .copy-feedback, #shared-link-feedback {
background-color: #2c2f33; background-color: #2c2f33;
padding: 6px 12px; padding-inline: 12px;
padding-block: 6px;
margin-top: 6px; margin-top: 6px;
border-radius: 6px; border-radius: 6px;
color: #00ff99; color: #28E060;
font-size: 0.9em; font-size: 0.9em;
display: none; display: none;
opacity: 0; opacity: 0;
@@ -361,7 +584,6 @@ footer {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 8px;
margin-top: 12px; margin-top: 12px;
margin-bottom: 12px; margin-bottom: 12px;
} }
@@ -369,9 +591,10 @@ footer {
#share-link { #share-link {
display: block; display: block;
background-color: #2c2f33; background-color: #2c2f33;
padding: 8px 16px; padding-inline: 16px;
padding-block: 8px;
border-radius: 6px; border-radius: 6px;
color: #00ff99; color: #28E060;
font-size: 0.9em; font-size: 0.9em;
text-align: center; text-align: center;
max-width: 720px; max-width: 720px;
@@ -394,11 +617,6 @@ form {
align-items: center; align-items: center;
} }
form input {
width: 80%;
max-width: 500px;
text-align: left;
}
/* ===== Section Card Styling ===== */ /* ===== Section Card Styling ===== */
section.card { section.card {
@@ -411,7 +629,7 @@ section.card {
#pacmanCanvas { #pacmanCanvas {
background-color: black; background-color: black;
display: block; display: block;
border: 2px solid #00ff99; border: 2px solid #28E060;
border-radius: 12px; border-radius: 12px;
max-width: 700px; max-width: 700px;
width: 100%; width: 100%;
@@ -423,7 +641,6 @@ section.card {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 20px;
margin-bottom: 25px; margin-bottom: 25px;
max-width: 725px; max-width: 725px;
width: 100%; width: 100%;
@@ -533,7 +750,7 @@ section.card {
padding: 25px; padding: 25px;
background-color: #1e1e1e; background-color: #1e1e1e;
border-radius: 12px; border-radius: 12px;
box-shadow: 0 0 15px rgba(0, 255, 153, 0.4); box-shadow: 0 0 15px #28E060;
} }
.sitemap-header { .sitemap-header {
@@ -544,17 +761,18 @@ section.card {
} }
.sitemap-header h3 { .sitemap-header h3 {
color: #00ff99; color: #28E060;
margin: 0; margin: 0;
} }
.collapse-btn { .collapse-btn {
background: none; background: none;
border: none; border: none;
color: #00ff99; color: #28E060;
font-size: 1.2em; font-size: 1.2em;
cursor: pointer; cursor: pointer;
padding: 5px 10px; padding-inline: 10px;
padding-block: 5px;
transition: transform 0.3s ease; transition: transform 0.3s ease;
} }
@@ -576,11 +794,11 @@ section.card {
#sitemap-section li, #sitemap-section li,
#server-status-section li { #server-status-section li {
margin-bottom: 10px; margin-bottom: 6px;
padding: 8px; padding: 8px;
background-color: #2c2f33; background-color: #2c2f33;
border-radius: 6px; border-radius: 6px;
color: #00ff99; color: #28E060;
} }
#server-logs-section button { #server-logs-section button {
@@ -590,14 +808,14 @@ section.card {
} }
#logLoader { #logLoader {
color: #00ff99; color: #28E060;
text-align: center; text-align: center;
padding: 10px; padding: 10px;
} }
#logContainer { #logContainer {
background-color: #2c2f33; background-color: #2c2f33;
color: #00ff99; color: #28E060;
padding: 15px; padding: 15px;
border-radius: 8px; border-radius: 8px;
max-height: 400px; max-height: 400px;
@@ -611,29 +829,5 @@ section.card {
padding: 25px; padding: 25px;
background-color: #1e1e1e; background-color: #1e1e1e;
border-radius: 12px; border-radius: 12px;
box-shadow: 0 0 15px rgba(0, 255, 153, 0.4); box-shadow: 0 0 15px #28E060;
}
/* ===== Mobile Responsive Adjustments ===== */
@media (max-width: 768px) {
#sitemap-section,
#password-change-section,
#server-update-section,
#server-status-section,
#server-logs-section,
#system-settings-section {
padding: 20px;
margin-bottom: 20px;
}
#sitemap-section li,
#server-status-section li {
font-size: 0.9em;
padding: 6px;
}
#logContainer {
font-size: 0.9em;
padding: 10px;
}
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 300 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 KiB

+53 -1
View File
@@ -52,7 +52,11 @@ function setupElementListeners(elements) {
elements.generateBtn.addEventListener("click", generateRandomPassword); elements.generateBtn.addEventListener("click", generateRandomPassword);
elements.copyPasswordBtn.addEventListener("click", () => copyToClipboard("generated-password", "password-copy-feedback")); elements.copyPasswordBtn.addEventListener("click", () => copyToClipboard("generated-password", "password-copy-feedback"));
elements.copyOutputBtn?.addEventListener("click", () => copyToClipboard("output-text", "output-copy-feedback")); elements.copyOutputBtn?.addEventListener("click", () => copyToClipboard("output-text", "output-copy-feedback"));
elements.toggleSwitch.addEventListener("change", updateToggleLabels); elements.toggleSwitch.addEventListener("change", () => {
console.log("Mode:", elements.toggleSwitch.checked ? "Decrypt" : "Encrypt");
});
// Add file input change listener // Add file input change listener
const fileInput = document.getElementById("file-input"); const fileInput = document.getElementById("file-input");
@@ -294,6 +298,54 @@ function checkForPacman() {
window.exitGame(); window.exitGame();
} }
} }
function copyShareLink() {
const linkEl = document.getElementById("share-link");
const feedback = document.getElementById("shared-link-feedback");
if (!linkEl) return;
const linkText = linkEl.href || linkEl.textContent.trim();
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(linkText).then(() => {
showCopyFeedback(feedback);
}).catch(() => {
fallbackCopy(linkText, feedback);
});
} else {
fallbackCopy(linkText, feedback);
}
}
function fallbackCopy(text, feedbackEl) {
const tempInput = document.createElement("input");
tempInput.value = text;
document.body.appendChild(tempInput);
tempInput.select();
try {
document.execCommand("copy");
showCopyFeedback(feedbackEl);
} catch (err) {
alert("Copy failed. Please copy manually.");
}
document.body.removeChild(tempInput);
}
function showCopyFeedback(feedbackEl) {
if (!feedbackEl) return;
feedbackEl.style.display = "block";
feedbackEl.classList.add("show");
setTimeout(() => {
feedbackEl.classList.remove("show");
setTimeout(() => {
feedbackEl.style.display = "none";
}, 300);
}, 3000);
}
function startPacman() { } function startPacman() { }
function exitGame() { } function exitGame() { }
+13 -8
View File
@@ -10,31 +10,36 @@
<link rel="icon" type="image/png" href="{{ url_for('static', filename='img/PacCrypt.png') }}" /> <link rel="icon" type="image/png" href="{{ url_for('static', filename='img/PacCrypt.png') }}" />
<!-- Stylesheets --> <!-- Stylesheets -->
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" /> <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" />
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
<!-- Scripts --> <!-- Scripts -->
<script type="module" src="{{ url_for('static', filename='js/main.js') }}"></script> <script type="module" src="{{ url_for('static', filename='js/main.js') }}"></script>
</head> </head>
<body class="dark"> <body class="dark">
<!-- Header --> <!-- Header -->
<header class="card"> <header class="card logo-header">
<h1>PacCrypt</h1> <div class="logo-container">
<p>Encrypt and share your text or files securely</p> <img src="{{ url_for('static', filename='img/PacCrypt.png') }}" alt="PacCrypt Logo" />
</header> <div class="logo-text">
<h1>PACCRYPT</h1>
<p>Securely Share Text and Files</p>
</div>
</div>
</header>
<!-- Main Content --> <!-- Main Content -->
<main> <main>
<section class="card form-group" style="padding: 50px 30px;"> <section class="card form-group" style="padding: 50px 30px;">
<h2 style="color: #00ff99; font-size: 2.5em;">🚫 403 - Forbidden</h2> <h2 style="color: #00ff99; font-size: 2.5em;">403 - Forbidden</h2>
<p class="mt-4" style="font-size: 1.2em; color: #cccccc;"> <p class="mt-4" style="font-size: 1.2em; color: #cccccc;">
Looks like this area is locked behind a secret ghost door! 🛡️👻 Looks like this area is locked behind a secret ghost door!
</p> </p>
<!-- Navigation --> <!-- Navigation -->
<div class="button-group mt-4"> <div class="button-group mt-4">
<a href="{{ url_for('index') }}"> <a href="{{ url_for('index') }}">
<button type="button">⬅️ Return Home</button> <button type="button">Return Home</button>
</a> </a>
</div> </div>
</section> </section>
+15 -10
View File
@@ -10,31 +10,36 @@
<link rel="icon" type="image/png" href="{{ url_for('static', filename='img/PacCrypt.png') }}" /> <link rel="icon" type="image/png" href="{{ url_for('static', filename='img/PacCrypt.png') }}" />
<!-- Stylesheets --> <!-- Stylesheets -->
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" /> <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" />
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
<!-- Scripts --> <!-- Scripts -->
<script type="module" src="{{ url_for('static', filename='js/main.js') }}"></script> <script type="module" src="{{ url_for('static', filename='js/main.js') }}"></script>
</head> </head>
<body class="dark"> <body class="dark">
<!-- Header --> <!-- Header -->
<header class="card"> <header class="card logo-header">
<h1>PacCrypt</h1> <div class="logo-container">
<p>Encrypt and share your text or files securely</p> <img src="{{ url_for('static', filename='img/PacCrypt.png') }}" alt="PacCrypt Logo" />
</header> <div class="logo-text">
<h1>PACCRYPT</h1>
<p>Securely Share Text and Files</p>
</div>
</div>
</header>
<!-- Main Content --> <!-- Main Content -->
<main> <main>
<section class="card form-group" style="padding: 50px 30px;"> <section class="card form-group" style="padding: 50px 30px;">
<h2 style="color: #ff0066; font-size: 2.5em;">404 - Not Found</h2> <h2 style="color: #ff0066; font-size: 2.5em;">404 - Not Found</h2>
<p class="mt-4" style="font-size: 1.2em; color: #cccccc;"> <p style="font-size: 1.2em; color: #cccccc;">
Whoops! That page doesn't seem to exist. Maybe it got encrypted? 🧩🔐 Whoops! That page doesn't seem to exist. Maybe it got encrypted?
</p> </p>
<!-- Navigation --> <!-- Navigation -->
<div class="button-group mt-4"> <div class="button-group">
<a href="{{ url_for('index') }}"> <a href="{{ url_for('index') }}">
<button type="button">⬅️ Return Home</button> <button type="button">Return Home</button>
</a> </a>
</div> </div>
</section> </section>
+13 -8
View File
@@ -10,32 +10,37 @@
<link rel="icon" type="image/png" href="{{ url_for('static', filename='img/PacCrypt.png') }}" /> <link rel="icon" type="image/png" href="{{ url_for('static', filename='img/PacCrypt.png') }}" />
<!-- Stylesheets --> <!-- Stylesheets -->
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" /> <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" />
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
<!-- Scripts --> <!-- Scripts -->
<script type="module" src="{{ url_for('static', filename='js/main.js') }}"></script> <script type="module" src="{{ url_for('static', filename='js/main.js') }}"></script>
</head> </head>
<body class="dark"> <body class="dark">
<!-- Header --> <!-- Header -->
<header class="card"> <header class="card logo-header">
<h1>PacCrypt</h1> <div class="logo-container">
<p>Encrypt and share your text or files securely</p> <img src="{{ url_for('static', filename='img/PacCrypt.png') }}" alt="PacCrypt Logo" />
</header> <div class="logo-text">
<h1>PACCRYPT</h1>
<p>Securely Share Text and Files</p>
</div>
</div>
</header>
<!-- Main Content --> <!-- Main Content -->
<main> <main>
<section class="card form-group" style="padding: 50px 30px;"> <section class="card form-group" style="padding: 50px 30px;">
<h2 style="color: #ff3300; font-size: 2.5em;">💥 500 - Server Error</h2> <h2 style="color: #ff3300; font-size: 2.5em;">500 - Server Error</h2>
<p class="mt-4" style="font-size: 1.2em; color: #cccccc;"> <p class="mt-4" style="font-size: 1.2em; color: #cccccc;">
Uh oh! The ghosts chomped the server wires. 🧟‍♂️👾 Uh oh! The ghosts chomped the server wires.
We're working on patching it up. We're working on patching it up.
</p> </p>
<!-- Navigation --> <!-- Navigation -->
<div class="button-group mt-4"> <div class="button-group mt-4">
<a href="{{ url_for('index') }}"> <a href="{{ url_for('index') }}">
<button type="button">⬅️ Return Home</button> <button type="button">Return Home</button>
</a> </a>
</div> </div>
</section> </section>
+37 -37
View File
@@ -10,24 +10,30 @@
<link rel="icon" type="image/png" href="{{ url_for('static', filename='img/PacCrypt.png') }}" /> <link rel="icon" type="image/png" href="{{ url_for('static', filename='img/PacCrypt.png') }}" />
<!-- Stylesheets --> <!-- Stylesheets -->
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" /> <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" />
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
<!-- Scripts --> <!-- Scripts -->
<script type="module" src="{{ url_for('static', filename='js/main.js') }}"></script> <script type="module" src="{{ url_for('static', filename='js/main.js') }}"></script>
</head> </head>
<body class="dark"> <body class="dark">
<!-- Header --> <!-- Header -->
<header class="card"> <header class="card logo-header">
<h1>PacCrypt Admin Panel</h1> <div class="logo-container">
<p>Site Overview & Controls</p> <img src="{{ url_for('static', filename='img/PacCrypt.png') }}" alt="PacCrypt Logo" />
</header> <div class="logo-text">
<h1>PACCRYPT</h1>
<p>ADMIN PANEL</p>
</div>
</div>
</header>
<!-- Main Content --> <!-- Main Content -->
<main> <main>
<!-- Site Map Section --> <!-- Site Map Section -->
<section id="sitemap-section" class="card form-group"> <section id="sitemap-section" class="card form-group">
<h2>💾 Server Management</h2> <h2>Server Management</h2>
<div class="sitemap-header"> <div class="sitemap-header">
<button onclick="toggleSitemap()" style="margin-bottom: 10px;">Show Site Map</button> <button onclick="toggleSitemap()" style="margin-bottom: 10px;">Show Site Map</button>
@@ -36,32 +42,25 @@
<div id="sitemap-list" class="sitemap-content" style="display: none;"> <div id="sitemap-list" class="sitemap-content" style="display: none;">
<ul style="list-style: none; padding-left: 0;"> <ul style="list-style: none; padding-left: 0;">
{% for route in routes %} {% for route in routes %}
<li style="margin-bottom: 5px;">🔗 <code>{{ route }}</code></li> <li style="margin-bottom: 5px;"><code>{{ route }}</code></li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
<!-- Action Buttons --> <!-- Server Management Buttons -->
<div class="button-group"> <div class="admin-button-grid">
<button onclick="restartServer()">🔁 Restart Server</button> <button onclick="restartServer()">Restart Server</button>
<a href="{{ url_for('admin_logout') }}"> <form action="{{ url_for('admin_logout') }}" method="GET" style="display: inline;">
<button type="button">🚪 Log Out</button> <button type="submit">Log Out</button>
</a> </form>
<button onclick="updateServer()">Update Server</button>
<form action="{{ url_for('admin_settings') }}" method="GET" style="display: inline;">
<button type="submit">Settings</button>
</form>
<button onclick="resetAdmin()" class="danger-button">Reset Admin</button>
<button onclick="clearUploads()" class="danger-button">Clear PacShare</button>
</div> </div>
<!-- Update and Settings Buttons -->
<div class="button-group">
<button onclick="updateServer()">🔁 Pull Latest Changes</button>
<a href="{{ url_for('admin_settings') }}">
<button type="button">🛠️ Manage Upload Settings</button>
</a>
</div>
<!-- Admin Reset and Clear Uploads Buttons -->
<div class="button-group">
<button onclick="resetAdmin()" class="danger-button">⚠️ Reset Admin</button>
<button onclick="clearUploads()" class="danger-button">🗑 Clear Uploaded Files</button>
</div>
<!-- Flash Messages --> <!-- Flash Messages -->
<div id="admin-feedback" class="copy-feedback" style="display: none;"></div> <div id="admin-feedback" class="copy-feedback" style="display: none;"></div>
@@ -69,7 +68,7 @@
<!-- Password Change Section --> <!-- Password Change Section -->
<section id="password-change-section" class="card form-group"> <section id="password-change-section" class="card form-group">
<h2>🔑 Change Admin Password</h2> <h2>Change Admin Password</h2>
<!-- Password Feedback --> <!-- Password Feedback -->
{% with messages = get_flashed_messages(with_categories=true, category_filter=['password-feedback']) %} {% with messages = get_flashed_messages(with_categories=true, category_filter=['password-feedback']) %}
@@ -88,19 +87,20 @@
<!-- Server Status Section --> <!-- Server Status Section -->
<section id="server-status-section" class="card form-group"> <section id="server-status-section" class="card form-group">
<h2>📊 Server Status</h2> <h2>Server Status</h2>
<ul style="list-style: none; padding-left: 0;"> <ul class="status-list">
<li>🕒 Uptime: <code>{{ server_info.uptime }}</code></li> <li>Uptime: <code>{{ server_info.uptime }}</code></li>
<li>📅 Server Time: <code>{{ server_info.time }}</code></li> <li>Server Time: <code>{{ server_info.server_time }}</code></li>
<li>🐍 Python Version: <code>{{ server_info.python }}</code></li> <li>Python Version: <code>{{ server_info.python_version }}</code></li>
<li>⚙️ Flask Debug Mode: <code>{{ server_info.debug }}</code></li> <li>Flask Debug Mode: <code>{{ server_info.debug_mode }}</code></li>
</ul> </ul>
</section> </section>
<!-- Server Logs Section --> <!-- Server Logs Section -->
<section id="server-logs-section" class="card form-group"> <section id="server-logs-section" class="card form-group">
<h2>📜 Server Logs</h2> <h2>Server Logs</h2>
<button onclick="toggleLogs()" style="margin-bottom: 10px;">🔽 Show/Hide Logs</button> <button onclick="toggleLogs()" style="margin-bottom: 10px;">Show/Hide Logs</button>
<div id="logLoader" style="display: none; margin-bottom: 10px;">Loading logs...</div> <div id="logLoader" style="display: none; margin-bottom: 10px;">Loading logs...</div>
<pre id="logContainer" style="display: none;"></pre> <pre id="logContainer" style="display: none;"></pre>
</section> </section>
@@ -123,10 +123,10 @@
const logLoader = document.getElementById('logLoader'); const logLoader = document.getElementById('logLoader');
if (logContainer.style.display === 'none') { if (logContainer.style.display === 'none') {
logLoader.style.display = 'block'; logLoader.style.display = 'block';
const response = await fetch('{{ url_for('admin_logs') }}'); const response = await fetch("{{ url_for('admin_logs') }}");
const data = await response.json(); const data = await response.json();
logLoader.style.display = 'none'; logLoader.style.display = 'none';
logContainer.innerText = data.logs.join('\\n'); logContainer.innerText = data.logs.join('\n');
logContainer.style.display = 'block'; logContainer.style.display = 'block';
} else { } else {
logContainer.style.display = 'none'; logContainer.style.display = 'none';
+12 -8
View File
@@ -10,24 +10,28 @@
<link rel="icon" type="image/png" href="{{ url_for('static', filename='img/PacCrypt.png') }}" /> <link rel="icon" type="image/png" href="{{ url_for('static', filename='img/PacCrypt.png') }}" />
<!-- Stylesheets --> <!-- Stylesheets -->
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" /> <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" />
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
<!-- Scripts --> <!-- Scripts -->
<script type="module" src="{{ url_for('static', filename='js/main.js') }}"></script> <script type="module" src="{{ url_for('static', filename='js/main.js') }}"></script>
</head> </head>
<body class="dark"> <body class="dark">
<!-- Header --> <!-- Header -->
<header class="card"> <header class="card logo-header">
<h1>PacCrypt Admin</h1> <div class="logo-container">
<p>Administrator Login</p> <img src="{{ url_for('static', filename='img/PacCrypt.png') }}" alt="PacCrypt Logo" />
</header> <div class="logo-text">
<h1>PACCRYPT</h1>
<p>Admin Login</p>
</div>
</div>
</header>
<!-- Main Content --> <!-- Main Content -->
<main> <main>
<!-- Login Form Section --> <!-- Login Form Section -->
<section class="card form-group"> <section class="card form-group">
<h2>🔑 Admin Login</h2> <h2>Admin Login</h2>
<!-- Flash Messages --> <!-- Flash Messages -->
{% with messages = get_flashed_messages() %} {% with messages = get_flashed_messages() %}
@@ -41,7 +45,7 @@
<input type="text" name="username" placeholder="Username" required /> <input type="text" name="username" placeholder="Username" required />
<input type="password" name="password" placeholder="Password" required /> <input type="password" name="password" placeholder="Password" required />
<div class="button-group mt-3"> <div class="button-group mt-3">
<button type="submit">🚪 Log In</button> <button type="submit">Log In</button>
</div> </div>
</form> </form>
</section> </section>
+15 -9
View File
@@ -10,21 +10,27 @@
<link rel="icon" type="image/png" href="{{ url_for('static', filename='img/PacCrypt.png') }}" /> <link rel="icon" type="image/png" href="{{ url_for('static', filename='img/PacCrypt.png') }}" />
<!-- Stylesheets --> <!-- Stylesheets -->
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" /> <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" />
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
</head> </head>
<body class="dark"> <body class="dark">
<!-- Header --> <!-- Header -->
<header class="card"> <!-- Header -->
<h1>PacCrypt Admin Settings</h1> <header class="card logo-header">
<p>Manage upload configuration</p> <div class="logo-container">
</header> <img src="{{ url_for('static', filename='img/PacCrypt.png') }}" alt="PacCrypt Logo" />
<div class="logo-text">
<h1>PACCRYPT</h1>
<p>Server Settings</p>
</div>
</div>
</header>
<!-- Main Content --> <!-- Main Content -->
<main> <main>
<!-- Settings Form Section --> <!-- Settings Form Section -->
<section class="card form-group"> <section class="card form-group">
<h2>⚙️ Upload Settings</h2> <h2>Upload Settings</h2>
<!-- Flash Messages --> <!-- Flash Messages -->
{% with messages = get_flashed_messages() %} {% with messages = get_flashed_messages() %}
@@ -50,9 +56,9 @@
<!-- Action Buttons --> <!-- Action Buttons -->
<div class="button-group mt-4"> <div class="button-group mt-4">
<button type="submit">💾 Save Settings</button> <button type="submit">Save Settings</button>
<a href="{{ url_for('admin_page') }}"> <a href="{{ url_for('admin_page') }}">
<button type="button">⬅️ Back to Admin Panel</button> <button type="button">Back to Admin Panel</button>
</a> </a>
</div> </div>
</form> </form>
+13 -8
View File
@@ -4,30 +4,35 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="PacCrypt - Admin Setup" /> <meta name="description" content="PacCrypt - Admin Setup" />
<title>Admin Setup - PacCrypt</title> <title>PacCrypt - Admin Setup</title>
<!-- Favicon --> <!-- Favicon -->
<link rel="icon" type="image/png" href="{{ url_for('static', filename='img/PacCrypt.png') }}" /> <link rel="icon" type="image/png" href="{{ url_for('static', filename='img/PacCrypt.png') }}" />
<!-- Stylesheets --> <!-- Stylesheets -->
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" /> <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" />
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
<!-- Scripts --> <!-- Scripts -->
<script type="module" src="{{ url_for('static', filename='js/main.js') }}"></script> <script type="module" src="{{ url_for('static', filename='js/main.js') }}"></script>
</head> </head>
<body class="dark"> <body class="dark">
<!-- Header --> <!-- Header -->
<header class="card"> <header class="card logo-header">
<h1>PacCrypt Admin</h1> <div class="logo-container">
<p>Admin Setup</p> <img src="{{ url_for('static', filename='img/PacCrypt.png') }}" alt="PacCrypt Logo" />
</header> <div class="logo-text">
<h1>PACCRYPT</h1>
<p>Admin Setup</p>
</div>
</div>
</header>
<!-- Main Content --> <!-- Main Content -->
<main> <main>
<!-- Setup Form Section --> <!-- Setup Form Section -->
<section class="card form-group"> <section class="card form-group">
<h2>🛡️ Create Admin Account</h2> <h2>Create Admin Account</h2>
<!-- Flash Messages --> <!-- Flash Messages -->
{% with messages = get_flashed_messages() %} {% with messages = get_flashed_messages() %}
@@ -41,7 +46,7 @@
<input type="text" name="username" placeholder="Username" required /> <input type="text" name="username" placeholder="Username" required />
<input type="password" name="password" placeholder="Password" required /> <input type="password" name="password" placeholder="Password" required />
<div class="button-group mt-3"> <div class="button-group mt-3">
<button type="submit">📝 Set Credentials</button> <button type="submit">Set Credentials</button>
</div> </div>
</form> </form>
</section> </section>
+35 -30
View File
@@ -4,35 +4,40 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="PacCrypt - Secure text and file encryption with password generation" /> <meta name="description" content="PacCrypt - Secure text and file encryption with password generation" />
<title>PacCrypt - Encrypt and share your text or files securely</title> <title>PacCrypt</title>
<!-- Favicon --> <!-- Favicon -->
<link rel="icon" href="{{ url_for('static', filename='img/PacCrypt.png') }}" type="image/png" /> <link rel="icon" href="{{ url_for('static', filename='img/PacCrypt.png') }}" type="image/png" />
<!-- Stylesheets --> <!-- Stylesheets -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" /> <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" />
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
<!-- Scripts --> <!-- Scripts -->
<script type="module" src="{{ url_for('static', filename='js/main.js') }}" defer></script> <script type="module" src="{{ url_for('static', filename='js/main.js') }}" defer></script>
</head> </head>
<body class="dark"> <body class="dark">
<!-- Header --> <!-- Header -->
<header class="card"> <header class="card logo-header">
<h1>PacCrypt</h1> <div class="logo-container">
<p>Encrypt and share your text or files securely</p> <img src="{{ url_for('static', filename='img/PacCrypt.png') }}" alt="PacCrypt Logo" />
</header> <div class="logo-text">
<h1>PACCRYPT</h1>
<p>Securely Share Text and Files</p>
</div>
</div>
</header>
<!-- Main Content --> <!-- Main Content -->
<main> <main>
<!-- Password Generator Section --> <!-- Password Generator Section -->
<section id="password-generator-section" class="card form-group"> <section id="password-generator-section" class="card form-group">
<h2>🔑 Password Generator</h2> <h2>Password Generator</h2>
<div class="form-group"> <div class="form-group">
<input type="text" id="generated-password" readonly /> <input type="text" id="generated-password" readonly />
<div class="button-group"> <div class="button-group">
<button type="button" id="generate-btn">🎲 Generate</button> <button type="button" id="generate-btn">Generate</button>
<button type="button" id="copy-btn">📋 Copy Password</button> <button type="button" id="copy-btn">Copy Password</button>
</div> </div>
<div id="password-copy-feedback" class="copy-feedback">Password copied to clipboard!</div> <div id="password-copy-feedback" class="copy-feedback">Password copied to clipboard!</div>
</div> </div>
@@ -44,7 +49,7 @@
<canvas id="pacmanCanvas" width="800" height="600"></canvas> <canvas id="pacmanCanvas" width="800" height="600"></canvas>
</div> </div>
<audio id="chomp-sound" src="{{ url_for('static', filename='audio/chomp.mp3') }}"></audio> <audio id="chomp-sound" src="{{ url_for('static', filename='audio/chomp.mp3') }}"></audio>
<div class="button-group"> <div class="button-group" style="margin-top: 6px;">
<button type="button" onclick="resetGame()">Restart Game</button> <button type="button" onclick="resetGame()">Restart Game</button>
<button type="button" onclick="exitGame()">Exit Game</button> <button type="button" onclick="exitGame()">Exit Game</button>
</div> </div>
@@ -52,7 +57,7 @@
<!-- Encryption/Decryption Section --> <!-- Encryption/Decryption Section -->
<section id="encoding-section" class="card form-group"> <section id="encoding-section" class="card form-group">
<h2>🔐 Encrypt & Decrypt</h2> <h2>Encrypt & Decrypt</h2>
<form id="crypto-form" class="form-group"> <form id="crypto-form" class="form-group">
<!-- Encryption Type Selection --> <!-- Encryption Type Selection -->
<div class="form-group"> <div class="form-group">
@@ -65,13 +70,14 @@
<!-- Operation Toggle --> <!-- Operation Toggle -->
<div class="toggle-container"> <div class="toggle-container">
<span id="toggle-left-label">Encrypt</span> <span class="toggle-label">Encrypt</span>
<label class="switch"> <label class="material-switch">
<input type="checkbox" id="operation-toggle" /> <input type="checkbox" id="operation-toggle">
<span class="slider round"></span> <span class="material-slider"></span>
</label> </label>
<span id="toggle-right-label">Decrypt</span> <span class="toggle-label">Decrypt</span>
</div> </div>
<!-- Text Input Section --> <!-- Text Input Section -->
<div id="text-section" class="form-group"> <div id="text-section" class="form-group">
@@ -86,19 +92,19 @@
<!-- File Input Section --> <!-- File Input Section -->
<div id="file-section" class="form-group" style="display: none;"> <div id="file-section" class="form-group" style="display: none;">
<input type="file" id="file-input" /> <input type="file" id="file-input" />
<button type="button" id="remove-file-btn">🗑 Remove File</button> <button type="button" id="remove-file-btn">Remove File</button>
</div> </div>
<!-- Action Buttons --> <!-- Action Buttons -->
<div class="button-group"> <div class="button-group">
<button type="submit">Execute</button> <button type="submit">Execute</button>
<button type="button" id="copy-output-btn">📋 Copy Output</button> <button type="button" id="copy-output-btn">Copy Output</button>
</div> </div>
<!-- Output Section --> <!-- Output Section -->
<textarea id="output-text" readonly placeholder="Encrypted/Decrypted text will appear here..."></textarea> <textarea id="output-text" readonly placeholder="Encrypted/Decrypted Output"></textarea>
<div class="button-group"> <div class="button-group">
<button type="button" id="clear-all-btn" class="danger-button">🧹 Clear All</button> <button type="button" id="clear-all-btn" class="danger-button">Clear All</button>
</div> </div>
<div id="output-copy-feedback" class="copy-feedback">Text copied to clipboard!</div> <div id="output-copy-feedback" class="copy-feedback">Text copied to clipboard!</div>
</form> </form>
@@ -106,9 +112,8 @@
<!-- File Sharing Section --> <!-- File Sharing Section -->
<section id="sharing-section" class="card form-group"> <section id="sharing-section" class="card form-group">
<h2>📤 PacCrypt Share</h2> <h2 style="margin-bottom: unset;">PacShare</h2>
<h3>Securely share encrypted files.</h3> <p style="margin-top: unset;">Securely share encrypted files.</p>
<p>Do not lose your passwords, data will be lost forever!</p>
<!-- Flash Messages --> <!-- Flash Messages -->
{% with messages = get_flashed_messages() %} {% with messages = get_flashed_messages() %}
@@ -120,8 +125,7 @@
{% if "pickup" in message %} {% if "pickup" in message %}
<div class="share-link-container"> <div class="share-link-container">
<a id="share-link" href="{{ message.split(' at ')[1] }}" target="_blank">{{ message.split(" at ")[1] }}</a> <a id="share-link" href="{{ message.split(' at ')[1] }}" target="_blank">{{ message.split(" at ")[1] }}</a>
<!--- <span id="share-link">{{ message.split(" at ")[1] }}</span> ---> <button type="button" onclick="copyShareLink()">Copy Link</button>
<button type="button" id="copy-share-btn">📋 Copy Link</button>
<div id="shared-link-feedback" class="copy-feedback">Link copied to clipboard!</div> <div id="shared-link-feedback" class="copy-feedback">Link copied to clipboard!</div>
</div> </div>
{% endif %} {% endif %}
@@ -132,11 +136,12 @@
{% endif %} {% endif %}
{% endwith %} {% endwith %}
<!-- File Upload Form --> <!-- File Upload Form -->
<!-- Share Link Container (initially hidden) --> <!-- Share Link Container (initially hidden) -->
<div class="share-link-container" id="share-link-container" style="display: none;"> <div class="share-link-container" id="share-link-container" style="display: none;">
<a id="share-link" href="#" target="_blank"></a> <a id="share-link" href="#" target="_blank"></a>
<button type="button" id="copy-share-btn">📋 Copy Link</button> <button type="button" id="copy-share-btn">Copy Link</button>
<div id="shared-link-feedback" class="copy-feedback">Link copied to clipboard!</div> <div id="shared-link-feedback" class="copy-feedback">Link copied to clipboard!</div>
</div> </div>
<form method="POST" enctype="multipart/form-data" class="form-group" id="upload-form"> <form method="POST" enctype="multipart/form-data" class="form-group" id="upload-form">
@@ -144,10 +149,10 @@
<input type="password" name="enc_password" placeholder="Encryption/Decryption Password" required /> <input type="password" name="enc_password" placeholder="Encryption/Decryption Password" required />
<input type="password" name="pickup_password" placeholder="Pickup Password" required /> <input type="password" name="pickup_password" placeholder="Pickup Password" required />
<div class="button-group"> <div class="button-group">
<button type="submit">🔒 Upload and Generate Link</button> <button type="submit">Upload and Generate Link</button>
</div> </div>
</form> </form>
<p style="color: #9c0000;">BOTH PASSWORDS ARE REQUIRED FOR PICKUP</p>
<script> <script>
document.getElementById('upload-form').addEventListener('submit', async (e) => { document.getElementById('upload-form').addEventListener('submit', async (e) => {
e.preventDefault(); e.preventDefault();
+13 -8
View File
@@ -11,20 +11,25 @@
<!-- Stylesheets --> <!-- Stylesheets -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" /> <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" />
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
</head> </head>
<body class="dark"> <body class="dark">
<!-- Header --> <!-- Header -->
<header class="card"> <header class="card logo-header">
<h1>PacCrypt</h1> <div class="logo-container">
<p>Secure File Pickup and Decryption</p> <img src="{{ url_for('static', filename='img/PacCrypt.png') }}" alt="PacCrypt Logo" />
</header> <div class="logo-text">
<h1>PACCRYPT</h1>
<p>Encrypted File Pickup</p>
</div>
</div>
</header>
<!-- Main Content --> <!-- Main Content -->
<main> <main>
<!-- File Pickup Section --> <!-- File Pickup Section -->
<section id="pickup-section" class="card form-group"> <section id="pickup-section" class="card form-group">
<h2>🔐 File Pickup</h2> <h2>File Pickup</h2>
<!-- Flash Messages --> <!-- Flash Messages -->
{% with messages = get_flashed_messages() %} {% with messages = get_flashed_messages() %}
@@ -61,14 +66,14 @@
</div> </div>
<div class="button-group"> <div class="button-group">
<button type="submit">📥 Decrypt and Download</button> <button type="submit">Decrypt and Download</button>
</div> </div>
</form> </form>
</section> </section>
<!-- Security Notice Section --> <!-- Security Notice Section -->
<section id="security-notice-section" class="card form-group"> <section id="security-notice-section" class="card form-group">
<h2>🛡️ Security Notice</h2> <h2>Security Notice</h2>
<p style="color: #00ff99; text-align: center;"> <p style="color: #00ff99; text-align: center;">
Make sure you're on the correct domain before entering any passwords.<br> Make sure you're on the correct domain before entering any passwords.<br>
Your file will be permanently deleted after download. Your file will be permanently deleted after download.