Compare commits

..

3 Commits
main ... a

Author SHA1 Message Date
1670f4d017 html update that actually will work with the latest html in main 2024-09-11 12:50:20 +02:00
590c3b8502 Delete .gitignore 2024-09-10 17:13:24 +02:00
realcgcristi
ac6e773bfc big html design update 2024-09-10 18:07:10 +03:00
22 changed files with 1083 additions and 5186 deletions

29
.gitignore vendored
View File

@ -1,29 +0,0 @@
# Ignore SQLite database
data.db
# Ignore uploads directory
/uploads/
# Python-related files
__pycache__/
*.py[cod]
*$py.class
# Virtual environment
venv/
env/
.env
# IDE-specific files
.vscode/
.idea/
# OS-specific files
.DS_Store
Thumbs.db
# Log files
*.log
# Temporary files
*.tmp

View File

@ -1,2 +1,30 @@
this repo is deprecated
https://github.com/spitkov/sxbin
## Text sharing, File sharing, link shortener.
### frontend and backend, easily configurable (thru editing the html files and the .py)
----------------
1. Introduction
</br>
</br>
</br>
As said above, this is a **simple & private** backend (app.py) and frontend (in /templates), which has these features:
- File Sharing (get a short link to share files, and when the link is opened it will show some information)
- Text Sharing (kind of a pastebin, it will show the text and when the text was made, again in a short link)
- URL Shortener (when hosting this, it will short an url, and give you a link, and when you open it, it will automatically redirect you to that website)
2. This is 100% **anonymous**, no one can see who created the links, etc.
3. The UI is simple.
4. This is very easily self-hostable </br> </br>
Rookie Mistake: when you self-host it, you can open it in localhost:7123, when making a file/paste/shortener don't share that localhost link, localhost is only accessible on YOUR network. - instead, u can host it with your domain.
</br>
</br>
5. This project is **COMPLETLY** open source.
</br>
</br>
6. You might need to install some pip packages, if you dont have them installed already download this repo and go into the folder and execute ```pip install -r requirements.txt```
</br>
</br>
7. Demo:
<video src="https://cgcristi.xyz/demo.mp4" controls></video>

1503
app.py

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,12 @@
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
api_key TEXT
);
CREATE TABLE IF NOT EXISTS content (
vanity TEXT PRIMARY KEY,
type TEXT NOT NULL,
data TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
user_id INTEGER,
is_private INTEGER DEFAULT 0,
password TEXT,
FOREIGN KEY (user_id) REFERENCES users (id)
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL
);

View File

@ -66,13 +66,7 @@
</br>
</br>
</br>
<div class="footer">
<p>
Source code on: <a href="https://git.spitkov.hu/cgcristi/aCloud" target="_blank">Spitkov's Git</a> |
<a href="https://office.bence.lol/form/#/2/form/view/z5Cf3CL6tZtPjzKsbcEPync6JE3iyMl22h6thUQg1a4/" target="_blank">Suggestions & Bugs</a> |
<a href="https://office.bence.lol/kanban/#/2/kanban/view/hx6RTcpN0pR7hc1HHkMzG4awMoMdHjR2zbHjG7Xh+wU/embed/" target="_blank">Todo List</a>
</p>
</div>
<p>Source code on: </p><a href="https://github.com/realcgcristi/aCloud" target="_blank">GitHub</a> | <a href="https://git.spitkov.hu/cgcristi/aCloud" target="_blank">Spitkov's Git</a>
</div>
</body>
</html>

View File

@ -1,62 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>API Documentation - sxbin</title>
<style>
/* Add your styles here */
</style>
</head>
<body>
<h1>sxbin API Documentation</h1>
<h2>Authentication</h2>
<p>All API requests require an API key to be sent in the X-API-Key header.</p>
<h2>Endpoints</h2>
<h3>Upload File</h3>
<pre>
POST /api/upload/file
Headers:
X-API-Key: your_api_key
Body: multipart/form-data
file: (binary)
</pre>
<p>Returns: JSON with file URL and deletion URL</p>
<h3>Upload Pastebin</h3>
<pre>
POST /api/upload/pastebin
Headers:
X-API-Key: your_api_key
Content-Type: application/json
Body:
{
"content": "Your pastebin content here"
}
</pre>
<p>Returns: JSON with pastebin URL and deletion URL</p>
<h3>Shorten URL</h3>
<pre>
POST /api/shorten
Headers:
X-API-Key: your_api_key
Content-Type: application/json
Body:
{
"url": "https://example.com/your-long-url-here"
}
</pre>
<p>Returns: JSON with shortened URL and deletion URL</p>
<h2>Error Handling</h2>
<p>All errors are returned as JSON with an "error" field describing the issue.</p>
<footer>
<p>For more information or support, please contact our team.</p>
</footer>
</body>
</html>

View File

@ -86,8 +86,6 @@
/* Ensure proper contrast for syntax highlighting */
.highlight pre {
color: var(--text-color);
white-space: pre-wrap;
word-wrap: break-word;
}
/* Override Pygments styles for dark mode */
@ -156,65 +154,42 @@
</head>
<body>
<div class="container">
<h2>Content</h2>
{% if content %}
<p>Uploaded by: {{ 'Anonymous' if content.username == 'None' else content.username }}</p>
<p>Created at: {{ content.created_at }}</p>
{% if highlighted_content %}
<style>{{ css|safe }}</style>
<div class="highlight">
{{ highlighted_content|safe }}
<h1>Content</h1>
{% if created_at %}
<p>Created at: {{ created_at }}</p>
{% endif %}
{% if language %}
<p>Detected Language: {{ language }}</p>
{% endif %}
<div class="button-container">
<button id="copy-button" onclick="copyToClipboard()">Copy Raw</button>
<a href="{{ url_for('raw_vanity', vanity=vanity) }}" target="_blank"><button>View Raw</button></a>
</div>
<button onclick="copyToClipboard()" class="btn">Copy</button>
<a href="{{ url_for('raw_vanity', vanity=content.vanity) }}" class="btn">View Raw</a>
{% if current_user.is_authenticated and current_user.id == content.user_id %}
<a href="{{ url_for('edit_content', vanity=content.vanity) }}" class="btn">Edit</a>
{% endif %}
{% elif url %}
<p>Shortened URL: <a href="{{ url }}">{{ url }}</a></p>
<button onclick="copyToClipboard()" class="btn">Copy URL</button>
{% elif raw_content %}
<pre style="white-space: pre-wrap; word-wrap: break-word;">{{ raw_content }}</pre>
<button onclick="copyToClipboard()" class="btn">Copy</button>
<a href="{{ url_for('raw_vanity', vanity=content.vanity) }}" class="btn">View Raw</a>
{% if current_user.is_authenticated and current_user.id == content.user_id %}
<a href="{{ url_for('edit_content', vanity=content.vanity) }}" class="btn">Edit</a>
{% endif %}
<div class="highlight">
{% if highlighted_content %}
{{ highlighted_content|safe }}
{% else %}
<p>No content available</p>
{% endif %}
{% if current_user.is_authenticated and current_user.id == content.user_id %}
<form action="{{ url_for('delete_content', vanity=content.vanity) }}" method="post" style="display: inline;">
<button type="submit" class="btn">Delete</button>
</form>
{% endif %}
{% else %}
<p>No content found.</p>
<pre>{{ content }}</pre>
{% endif %}
</div>
</div>
<button id="theme-toggle">Toggle Theme</button>
<script>
const rawContent = {{ raw_content|tojson|default('null') }};
const url = {{ url|tojson|default('null') }};
const rawContent = {{ raw_content|tojson }};
function copyToClipboard() {
let textToCopy = rawContent;
if (url) {
textToCopy = url;
}
if (textToCopy) {
navigator.clipboard.writeText(textToCopy).then(() => {
alert('Copied to clipboard!');
navigator.clipboard.writeText(rawContent).then(() => {
const copyButton = document.getElementById("copy-button");
const originalText = copyButton.textContent;
copyButton.textContent = "Copied!";
setTimeout(() => {
copyButton.textContent = originalText;
}, 2000);
}).catch(err => {
console.error('Failed to copy text: ', err);
});
} else {
console.error('No content to copy');
}
}
const themeToggle = document.getElementById('theme-toggle');

View File

@ -1,71 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Content Info</title>
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
margin: 0;
padding: 20px;
background-color: #1a1a1a;
color: #f0f0f0;
}
.container {
max-width: 800px;
margin: 0 auto;
}
h2 {
color: #4CAF50;
}
.info-item {
margin-bottom: 10px;
}
.btn {
display: inline-block;
background-color: #4CAF50;
color: white;
padding: 8px 12px;
text-decoration: none;
border-radius: 4px;
margin: 5px 0;
}
.btn:hover {
background-color: #45a049;
}
</style>
</head>
<body>
<div class="container">
<h2>Content Information</h2>
<div class="info-item"><strong>Type:</strong> {{ info.type }}</div>
<div class="info-item"><strong>Vanity URL:</strong> {{ info.vanity }}</div>
<div class="info-item"><strong>Created At:</strong> {{ info.created_at }}</div>
<div class="info-item"><strong>Uploaded By:</strong> {{ info.username }}</div>
{% if info.type == 'file' %}
<div class="info-item"><strong>Filename:</strong> {{ info.data }}</div>
{% if info.file_size %}
<div class="info-item"><strong>File Size:</strong> {{ info.file_size }} bytes</div>
{% endif %}
<a href="{{ url_for('redirect_vanity', vanity=info.vanity)|replace('/download', '') }}" class="btn">View/Embed</a>
<a href="{{ url_for('redirect_vanity', vanity=info.vanity) ~ ('/download' if '/download' not in url_for('redirect_vanity', vanity=info.vanity) else '') }}" class="btn">Download</a>
{% elif info.type == 'url' %}
<div class="info-item"><strong>Target URL:</strong> {{ info.data }}</div>
<a href="{{ url_for('redirect_vanity', vanity=info.vanity) }}" class="btn">Visit URL</a>
{% elif info.type == 'pastebin' %}
<a href="{{ url_for('redirect_vanity', vanity=info.vanity) }}" class="btn">View Pastebin</a>
<a href="{{ url_for('raw_vanity', vanity=info.vanity) }}" class="btn">View Raw</a>
{% endif %}
{% if current_user.is_authenticated and current_user.username == info.username %}
{% if info.type != 'file' or not info.is_media %}
<a href="{{ url_for('edit_content', vanity=info.vanity) }}" class="btn">Edit</a>
{% endif %}
<form action="{{ url_for('delete_content', vanity=info.vanity) }}" method="post" style="display: inline;">
<button type="submit" class="btn">Delete</button>
</form>
{% endif %}
</div>
</body>
</html>

View File

@ -1,68 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Edit Content</title>
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
margin: 0;
padding: 20px;
background-color: #1a1a1a;
color: #f0f0f0;
}
.container {
max-width: 800px;
margin: 0 auto;
}
h1 {
color: #4CAF50;
}
#editor {
width: 100%;
height: 400px;
font-family: monospace;
font-size: 14px;
background-color: #2a2a2a;
color: #f0f0f0;
border: 1px solid #4CAF50;
padding: 10px;
box-sizing: border-box;
}
input[type="submit"] {
background-color: #4CAF50;
color: white;
padding: 10px 20px;
border: none;
cursor: pointer;
font-size: 16px;
margin-top: 10px;
}
input[type="submit"]:hover {
background-color: #45a049;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js"></script>
</head>
<body>
<div class="container">
<h1>Edit Content</h1>
<form method="post">
<div id="editor">{{ content }}</div>
<input type="hidden" name="content" id="hidden-content">
<input type="submit" value="Save" onclick="updateContent()">
</form>
</div>
<script>
var editor = ace.edit("editor");
editor.setTheme("ace/theme/monokai");
editor.session.setMode("ace/mode/text");
function updateContent() {
document.getElementById('hidden-content').value = editor.getValue();
}
</script>
</body>
</html>

View File

@ -1,26 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Edit Password</title>
<style>
/* Add your styles here */
</style>
</head>
<body>
<div class="container">
<h2>Edit Password</h2>
<form method="POST">
<input type="password" name="new_password" placeholder="Enter new password">
<input type="hidden" name="action" value="update">
<button type="submit">Update Password</button>
</form>
<form method="POST">
<input type="hidden" name="action" value="remove">
<button type="submit">Remove Password</button>
</form>
<a href="{{ url_for('user_files', username=current_user.username) }}">Cancel</a>
</div>
</body>
</html>

View File

@ -1,165 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ filename }} - sxbin</title>
<meta property="og:title" content="{{ filename }}">
<meta property="og:type" content="website">
<meta property="og:url" content="{{ request.url }}">
<meta property="og:description" content="File size: {{ file_size|filesizeformat }} | Uploaded by: {{ username }} | Date: {{ created_at.strftime('%Y-%m-%d %H:%M:%S') }}{% if is_private %} | Password Protected{% endif %}">
{% if is_embeddable %}
<meta property="og:image" content="{{ raw_url }}">
{% endif %}
<meta property="og:site_name" content="sxbin">
<meta property="theme-color" content="#4CAF50">
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: #e0e0e0;
background-color: #1e1e1e;
margin: 0;
padding: 0;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
h2 {
color: #4CAF50;
}
.info-item {
margin-bottom: 10px;
}
.embed-container {
margin-top: 20px;
margin-bottom: 20px;
}
.embed-container img, .embed-container embed {
max-width: 100%;
max-height: 600px;
display: block;
margin: 0 auto;
}
.btn-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 20px;
}
.btn {
background-color: #4CAF50;
color: white;
border: none;
padding: 10px 15px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 14px;
margin: 4px 2px;
cursor: pointer;
border-radius: 4px;
transition: background-color 0.3s;
}
.btn:hover {
background-color: #45a049;
}
.home-button {
position: fixed;
top: 20px;
left: 20px;
font-size: 24px;
color: #4CAF50;
text-decoration: none;
}
.home-button:hover {
color: #45a049;
}
#theme-toggle {
position: fixed;
top: 20px;
right: 20px;
background-color: #333;
color: #fff;
border: none;
padding: 5px 10px;
cursor: pointer;
border-radius: 4px;
}
footer {
text-align: center;
margin-top: 20px;
padding: 10px;
background-color: #2a2a2a;
color: #f0f0f0;
}
.edit-btn, .delete-btn {
background-color: #f44336;
}
.edit-btn:hover, .delete-btn:hover {
background-color: #d32f2f;
}
</style>
</head>
<body>
<a href="/" class="home-button">&#8962;</a>
<div class="container">
<h2>{{ filename }}</h2>
<div class="info-item"><strong>File size:</strong> {{ file_size|filesizeformat }}</div>
<div class="info-item"><strong>Uploaded by:</strong> {{ username }}</div>
<div class="info-item"><strong>Date:</strong> {{ created_at.strftime('%Y-%m-%d %H:%M:%S') }}</div>
<div class="info-item"><strong>File type:</strong> {{ filename.split('.')[-1].upper() if '.' in filename else 'Unknown' }}</div>
{% if is_embeddable %}
<div class="embed-container">
{% if filename.lower().endswith(('.jpg', '.jpeg', '.png', '.gif', '.svg')) %}
<img src="{{ raw_url }}" alt="{{ filename }}">
{% elif filename.lower().endswith('.pdf') %}
<embed src="{{ raw_url }}" type="application/pdf" width="100%" height="600px">
{% endif %}
</div>
{% endif %}
<div class="btn-container">
<a href="{{ file_url }}/download{% if password %}/{{ password }}{% endif %}" class="btn">Download</a>
<a href="{{ raw_url }}" class="btn">View Raw</a>
{% if current_user.is_authenticated and current_user.id == user_id %}
{% if filename.lower().endswith(('.txt', '.html', '.css', '.js', '.py', '.md')) or '.' not in filename %}
<a href="{{ url_for('edit_content', vanity=vanity) }}" class="btn edit-btn">Edit</a>
{% endif %}
<form action="{{ url_for('delete_content', vanity=vanity) }}" method="post" style="display: inline;">
<button type="submit" class="btn delete-btn" onclick="return confirm('Are you sure you want to delete this file?')">Delete</button>
</form>
{% endif %}
</div>
</div>
<button id="theme-toggle">Toggle Theme</button>
<footer>
<p>
Source code: <a href="https://git.spitkov.hu/cgcristi/aCloud" target="_blank">Spitkov's Git</a> |
<a href="https://office.bence.lol/form/#/2/form/view/z5Cf3CL6tZtPjzKsbcEPync6JE3iyMl22h6thUQg1a4/" target="_blank">Suggestions & Bugs</a> |
<a href="https://office.bence.lol/kanban/#/2/kanban/view/hx6RTcpN0pR7hc1HHkMzG4awMoMdHjR2zbHjG7Xh+wU/embed/" target="_blank">Todo List</a>
</p>
</footer>
<script>
const themeToggle = document.getElementById('theme-toggle');
const body = document.body;
themeToggle.addEventListener('click', () => {
body.classList.toggle('light-mode');
localStorage.setItem('theme', body.classList.contains('light-mode') ? 'light' : 'dark');
});
// Check for saved theme preference
const savedTheme = localStorage.getItem('theme');
if (savedTheme === 'light') {
body.classList.add('light-mode');
}
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -1,150 +1,6 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login - sxbin</title>
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
min-height: 100vh;
background-color: #1a1a1a;
color: #f0f0f0;
}
.content {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.container {
background-color: #2a2a2a;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
width: 300px;
}
h2 {
text-align: center;
color: #4CAF50;
}
form {
display: flex;
flex-direction: column;
}
label {
margin-bottom: 5px;
}
input[type="text"],
input[type="password"] {
padding: 8px;
margin-bottom: 10px;
border-radius: 4px;
border: 1px solid #4CAF50;
background-color: #333;
color: #f0f0f0;
}
button {
background-color: #4CAF50;
color: white;
padding: 10px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background-color: #45a049;
}
.remember-me {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.remember-me input {
margin-right: 5px;
}
p {
text-align: center;
margin-top: 15px;
}
a {
color: #4CAF50;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.back-button {
position: absolute;
top: 20px;
left: 20px;
font-size: 24px;
color: #4CAF50;
text-decoration: none;
}
.back-button:hover {
color: #45a049;
}
.footer {
text-align: center;
padding: 10px;
background-color: #2a2a2a;
color: #f0f0f0;
}
.error-message {
background-color: #ff6b6b;
color: white;
padding: 10px;
border-radius: 5px;
margin-bottom: 10px;
display: none;
}
</style>
</head>
<body>
<a href="/" class="back-button">&#8592;</a>
<div class="content">
<div class="container">
<h2>Login to sxbin</h2>
<div id="error-message" class="error-message"></div>
<form id="login-form" method="POST">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
<label>
<input type="checkbox" name="remember"> Remember me
</label>
<h2>Login</h2>
<form method="post">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<input type="submit" value="Login">
</form>
<p>Don't have an account? <a href="{{ url_for('register') }}">Register</a></p>
</div>
</div>
<script>
document.getElementById('login-form').addEventListener('submit', function(e) {
e.preventDefault();
fetch('/login', {
method: 'POST',
body: new FormData(this),
})
.then(response => response.json())
.then(data => {
if (data.success) {
window.location.href = data.redirect;
} else {
document.getElementById('error-message').textContent = data.error;
document.getElementById('error-message').style.display = 'block';
}
});
});
</script>
</body>
</html>
</form>

View File

@ -1,22 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ filename }} - sxbin</title>
<meta property="og:title" content="{{ filename }}">
<meta property="og:type" content="website">
<meta property="og:url" content="{{ request.url }}">
<meta property="og:description" content="File size: {{ file_size|filesizeformat }} | Uploaded by: {{ username }} | Date: {{ created_at.strftime('%Y-%m-%d %H:%M:%S') }}">
{% if is_embeddable %}
<meta property="og:image" content="{{ file_url }}/raw">
{% endif %}
<meta property="og:site_name" content="sxbin">
<meta property="theme-color" content="#4CAF50">
</head>
<body>
<script>
window.location.href = "{{ file_url }}";
</script>
</body>
</html>

View File

@ -1,20 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pastebin {{ vanity }} - sxbin</title>
<meta property="og:title" content="Pastebin {{ vanity }}">
<meta property="og:type" content="website">
<meta property="og:url" content="{{ request.url }}">
<meta property="og:description" content="{{ first_lines|truncate(200) }}">
<meta property="og:site_name" content="sxbin">
<meta property="theme-color" content="#4CAF50">
</head>
<body>
<h1>Pastebin {{ vanity }}</h1>
<pre>{{ first_lines }}</pre>
<p>Created by: {{ username }}</p>
<p>Date: {{ created_at.strftime('%Y-%m-%d %H:%M:%S') }}</p>
</body>
</html>

View File

@ -1,24 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Shortened URL - sxbin</title>
<meta property="og:title" content="Shortened URL - sxbin">
<meta property="og:type" content="website">
<meta property="og:url" content="{{ request.url }}">
<meta property="og:description" content="Shortened URL {% if is_private %}(Password Protected){% endif %} | Created by: {{ username }} | Date: {{ created_at.strftime('%Y-%m-%d %H:%M:%S') }}">
<meta property="og:site_name" content="sxbin">
<meta property="theme-color" content="#4CAF50">
</head>
<body>
<h1>Shortened URL</h1>
<p>Original URL: {{ long_url }}</p>
<p>Created by: {{ username }}</p>
<p>Date: {{ created_at.strftime('%Y-%m-%d %H:%M:%S') }}</p>
{% if is_private %}
<p>This URL is password protected.</p>
{% endif %}
<a href="{{ url_for('redirect_vanity', vanity=vanity) }}">Access the URL</a>
</body>
</html>

View File

@ -1,28 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Password Protected Content - sxbin</title>
<meta property="og:title" content="Password Protected Content - sxbin">
<meta property="og:type" content="website">
<meta property="og:url" content="{{ request.url }}">
<meta property="og:description" content="This {{ content_type }} is password protected. Enter the password to view.">
<meta property="og:site_name" content="sxbin">
<meta property="theme-color" content="#4CAF50">
<style>
/* Add your styles here */
</style>
</head>
<body>
<h1>Password Protected Content</h1>
<p>This {{ content_type }} is password protected. Please enter the password to view.</p>
{% if error %}
<p style="color: red;">{{ error }}</p>
{% endif %}
<form method="POST">
<input type="password" name="password" required>
<button type="submit">Submit</button>
</form>
</body>
</html>

View File

@ -3,230 +3,52 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pastebin {{ vanity }} - sxbin</title>
<meta property="og:title" content="Pastebin {{ vanity }} - sxbin">
<meta property="og:type" content="website">
<meta property="og:url" content="{{ request.url }}">
<meta property="og:description" content="Pastebin{% if is_private %} (Password Protected){% endif %} | Uploaded by: {{ content.username }} | Date: {{ created_at.strftime('%Y-%m-%d %H:%M:%S') }}">
<meta property="og:site_name" content="sxbin">
<meta property="theme-color" content="#4CAF50">
<title>Pastebin Content</title>
<style>
:root {
--bg-color: #1e1e1e;
--text-color: #e0e0e0;
--highlight-bg: #2d2d2d;
--highlight-border: #444;
--button-bg: #3a3a3a;
--button-text: #e0e0e0;
}
.light-mode {
--bg-color: #ffffff;
--text-color: #333333;
--highlight-bg: #f8f8f8;
--highlight-border: #ccc;
--button-bg: #f0f0f0;
--button-text: #333333;
}
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: var(--text-color);
background-color: var(--bg-color);
transition: background-color 0.3s, color 0.3s;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
h1, h2 {
margin-bottom: 20px;
}
{{ css|safe }}
/* Add any additional styles here */
.button-container {
margin-bottom: 20px;
margin-bottom: 10px;
}
button {
background-color: var(--button-bg);
color: var(--button-text);
border: none;
padding: 10px 15px;
.button-container button {
margin-right: 10px;
cursor: pointer;
border-radius: 4px;
transition: background-color 0.3s;
}
button:hover {
opacity: 0.8;
}
.highlight {
background-color: var(--highlight-bg);
border: 1px solid var(--highlight-border);
background-color: #f8f8f8;
border: 1px solid #ccc;
border-radius: 4px;
padding: 1em;
overflow: auto;
position: relative;
}
.highlight pre {
color: var(--text-color);
white-space: pre;
word-wrap: normal;
overflow-x: auto;
margin: 0;
padding: 0;
}
.highlight .linenos {
color: #999;
text-align: right;
padding-right: 10px;
border-right: 1px solid var(--highlight-border);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.highlight .code {
padding-left: 10px;
}
#theme-toggle {
position: fixed;
top: 20px;
right: 20px;
}
a {
color: var(--text-color);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.btn-container {
display: flex;
gap: 10px;
margin-top: 20px;
}
.btn {
background-color: var(--button-bg);
color: var(--button-text);
border: none;
padding: 10px 15px;
cursor: pointer;
border-radius: 4px;
transition: background-color 0.3s, opacity 0.3s;
text-decoration: none;
display: inline-block;
flex: 1;
text-align: center;
font-size: 14px;
}
.btn:hover {
opacity: 0.8;
}
form {
flex: 1;
display: flex;
}
form .btn {
width: 100%;
}
.home-button {
position: fixed;
top: 20px;
left: 20px;
font-size: 24px;
color: var(--text-color);
text-decoration: none;
z-index: 1001;
}
.home-button:hover {
color: #4CAF50;
}
{{ css|safe }}
</style>
</head>
<body>
<a href="/" class="home-button">&#8962;</a>
<div class="container">
<h2>Content</h2>
<p>Uploaded by: {{ 'Anonymous' if content.username == 'None' else content.username }}</p>
<h1>Pastebin Content</h1>
<p>Created at: {{ created_at }}</p>
<p>Detected Language: {{ language }}</p>
<div class="button-container">
<button id="copy-button" onclick="copyToClipboard()">Copy Raw</button>
<a href="{{ url_for('raw_vanity', vanity=vanity) }}" target="_blank"><button>View Raw</button></a>
</div>
<div class="highlight">
{{ highlighted_content|safe }}
{{ content|safe }}
</div>
<div class="btn-container">
<button onclick="copyToClipboard()" class="btn">Copy</button>
<a href="{{ url_for('raw_vanity', vanity=vanity) }}" class="btn">View Raw</a>
{% if current_user.is_authenticated and current_user.id == content.user_id %}
<a href="{{ url_for('edit_content', vanity=vanity) }}" class="btn">Edit</a>
{% if is_private %}
<button onclick="openEditPasswordModal()" class="btn">Edit Password</button>
{% else %}
<button onclick="openAddPasswordModal()" class="btn">Add Password</button>
{% endif %}
<form action="{{ url_for('delete_content', vanity=vanity) }}" method="post">
<button type="submit" class="btn">Delete</button>
</form>
{% endif %}
</div>
</div>
<button id="theme-toggle">Toggle Theme</button>
<footer style="text-align: center; margin-top: 20px; padding: 10px; background-color: #2a2a2a; color: #f0f0f0;">
<p>
Source code: <a href="https://git.spitkov.hu/cgcristi/aCloud" target="_blank">Spitkov's Git</a> |
<a href="https://office.bence.lol/form/#/2/form/view/z5Cf3CL6tZtPjzKsbcEPync6JE3iyMl22h6thUQg1a4/" target="_blank">Suggestions & Bugs</a> |
<a href="https://office.bence.lol/kanban/#/2/kanban/view/hx6RTcpN0pR7hc1HHkMzG4awMoMdHjR2zbHjG7Xh+wU/embed/" target="_blank">Todo List</a>
</p>
</footer>
<script>
const rawContent = {{ raw_content|tojson }};
function copyToClipboard() {
navigator.clipboard.writeText(rawContent).then(() => {
alert('Copied to clipboard!');
const copyButton = document.getElementById("copy-button");
const originalText = copyButton.textContent;
copyButton.textContent = "Copied!";
setTimeout(() => {
copyButton.textContent = originalText;
}, 2000);
}).catch(err => {
console.error('Failed to copy text: ', err);
});
}
const themeToggle = document.getElementById('theme-toggle');
const html = document.documentElement;
function toggleTheme() {
html.classList.toggle('light-mode');
localStorage.setItem('lightMode', html.classList.contains('light-mode'));
}
themeToggle.addEventListener('click', toggleTheme);
// Check for saved theme preference
if (localStorage.getItem('lightMode') === 'true') {
html.classList.add('light-mode');
}
</script>
</body>
</html>

View File

@ -1,171 +1,6 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Register - sxbin</title>
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
min-height: 100vh;
background-color: #1a1a1a;
color: #f0f0f0;
}
.content {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.container {
background-color: #2a2a2a;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
width: 300px;
}
h2 {
text-align: center;
color: #4CAF50;
}
form {
display: flex;
flex-direction: column;
}
label {
margin-bottom: 5px;
}
input[type="text"],
input[type="password"] {
padding: 8px;
margin-bottom: 10px;
border-radius: 4px;
border: 1px solid #4CAF50;
background-color: #333;
color: #f0f0f0;
}
button {
background-color: #4CAF50;
color: white;
padding: 10px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background-color: #45a049;
}
p {
text-align: center;
margin-top: 15px;
}
a {
color: #4CAF50;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.back-button {
position: absolute;
top: 20px;
left: 20px;
font-size: 24px;
color: #4CAF50;
text-decoration: none;
}
.back-button:hover {
color: #45a049;
}
.footer {
text-align: center;
padding: 10px;
background-color: #2a2a2a;
color: #f0f0f0;
}
.error-message {
background-color: #ff6b6b;
color: white;
padding: 10px;
border-radius: 5px;
margin-bottom: 10px;
display: none;
}
.password-requirement {
font-size: 0.9em;
margin-top: 5px;
transition: color 0.3s ease;
}
.requirement-not-met {
color: #ff6b6b;
}
.requirement-met {
color: #4CAF50;
}
</style>
</head>
<body>
<a href="/" class="back-button">&#8592;</a>
<div class="content">
<div class="container">
<h2>Register for sxbin</h2>
<div id="error-message" class="error-message"></div>
<form id="register-form" method="POST">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
<div id="password-length" class="password-requirement requirement-not-met">At least 5 characters</div>
<div id="password-uppercase" class="password-requirement requirement-not-met">At least one uppercase letter</div>
<input type="submit" value="Register" id="submit-button" disabled>
</form>
<p>Already have an account? <a href="{{ url_for('login') }}">Login</a></p>
</div>
</div>
<script>
const passwordInput = document.getElementById('password');
const lengthRequirement = document.getElementById('password-length');
const uppercaseRequirement = document.getElementById('password-uppercase');
const submitButton = document.getElementById('submit-button');
passwordInput.addEventListener('input', function() {
const password = this.value;
const meetsLengthRequirement = password.length >= 5;
const meetsUppercaseRequirement = /[A-Z]/.test(password);
lengthRequirement.className = meetsLengthRequirement ? 'password-requirement requirement-met' : 'password-requirement requirement-not-met';
uppercaseRequirement.className = meetsUppercaseRequirement ? 'password-requirement requirement-met' : 'password-requirement requirement-not-met';
submitButton.disabled = !(meetsLengthRequirement && meetsUppercaseRequirement);
});
document.getElementById('register-form').addEventListener('submit', function(e) {
e.preventDefault();
fetch('/register', {
method: 'POST',
body: new FormData(this),
})
.then(response => response.json())
.then(data => {
if (data.success) {
window.location.href = data.redirect;
} else {
document.getElementById('error-message').textContent = data.error;
document.getElementById('error-message').style.display = 'block';
}
});
});
</script>
</body>
</html>
<h2>Register</h2>
<form method="post">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<input type="submit" value="Register">
</form>

File diff suppressed because it is too large Load Diff

View File

@ -16,19 +16,12 @@
h2 {
color: #4CAF50;
}
.file-list {
display: flex;
flex-wrap: wrap;
gap: 10px;
padding: 0;
ul {
list-style-type: none;
padding: 0;
}
.file-item {
background-color: #2a2a2a;
padding: 10px;
border-radius: 5px;
display: flex;
align-items: center;
li {
margin-bottom: 10px;
}
a {
color: #4CAF50;
@ -37,34 +30,13 @@
a:hover {
text-decoration: underline;
}
.folder {
font-weight: bold;
}
.file-icon {
margin-right: 5px;
}
</style>
</head>
<body>
<h2>{{ username }}'s Files</h2>
<p>Current folder: {{ current_folder or 'Root' }}</p>
{% if parent_url is not none %}
<p><a href="{{ parent_url }}">Parent Directory</a></p>
{% endif %}
<ul class="file-list">
{% for folder in folders %}
<li class="file-item folder">
<span class="file-icon">📁</span>
<a href="{{ url_for('serve_user_page', username=username, filename=folder.path) }}">{{ folder.name }}</a>
</li>
{% endfor %}
<ul>
{% for file in files %}
<li class="file-item">
<span class="file-icon">📄</span>
<a href="{{ url_for('serve_user_page', username=username, filename=file.path) }}">{{ file.name }}</a>
</li>
<li><a href="{{ url_for('download_folder_file', vanity=username, file_name=file) }}">{{ file }}</a></li>
{% endfor %}
</ul>
</body>

27
uploads/asdasd/index.html Normal file
View File

@ -0,0 +1,27 @@
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>&#80;&#121;&#116;&#104;&#111;&#110;&#32;&#73;&#68;&#69;</title><script src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython_stdlib.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/codemirror.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/mode/python/python.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/hint/show-hint.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/hint/python-hint.js"></script><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/codemirror.min.css"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/theme/monokai.min.css"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/hint/show-hint.css"><style>body{background-color:#1e1e1e;color:#d4d4d4;font-family:'Consolas','Courier New',monospace;margin:0;padding:20px}h1{color:#569cd6}#code{width:100%;height:300px}#output{width:100%;height:200px;background-color:#1e1e1e;border:1px solid #3c3c3c;padding:10px;margin-top:10px;overflow-y:auto;font-family:'Consolas','Courier New',monospace}#run-button,#save-button{background-color:#0e639c;color:white;border:none;padding:10px 20px;margin-top:10px;cursor:pointer}#run-button:hover,#save-button:hover{background-color:#1177bb}.toolbar{margin-bottom:10px}.toolbar button{background-color:#3c3c3c;color:#d4d4d4;border:none;padding:5px 10px;margin-right:5px;cursor:pointer}.toolbar button:hover{background-color:#4e4e4e}</style></head><body onload="brython()"><h1>&#80;&#121;&#116;&#104;&#111;&#110;&#32;&#73;&#68;&#69;</h1><div class="toolbar"><button id="undo-button">&#85;&#110;&#100;&#111;</button><button id="redo-button">&#82;&#101;&#100;&#111;</button><button id="save-button">&#83;&#97;&#118;&#101;</button></div><textarea id="code" placeholder="&#69;&#110;&#116;&#101;&#114;&#32;&#121;&#111;&#117;&#114;&#32;&#80;&#121;&#116;&#104;&#111;&#110;&#32;&#99;&#111;&#100;&#101;&#32;&#104;&#101;&#114;&#101;"></textarea><br><button id="run-button">&#82;&#117;&#110;</button><div id="output"></div><script type="text/python">from browser import document,window
import sys
class _0x1234:
def __init__(_0x5678):_0x5678._0x9abc=document["output"]
def write(_0x5678,_0xdef0):_0x5678._0x9abc.innerHTML+=_0xdef0
sys.stdout=_0x1234()
sys.stderr=_0x1234()
def _0x2345(_0x6789):
document["output"].innerHTML=""
_0xabcd=window.editor.getValue()
try:exec(_0xabcd)
except Exception as _0xef01:print(f"Error: {str(_0xef01)}")
document["run-button"].bind("click",_0x2345)
def _0x3456(_0x789a):window.editor.undo()
def _0x4567(_0x89ab):window.editor.redo()
document["undo-button"].bind("click",_0x3456)
document["redo-button"].bind("click",_0x4567)
def _0x5678(_0x9abc):
_0xbcde=window.editor.getValue()
_0xcdef=window.Blob.new([_0xbcde],{'type':'text/plain'})
_0xdef0=window.URL.createObjectURL(_0xcdef)
_0xef01=document.createElement('a')
_0xef01.href=_0xdef0
_0xef01.download='python_code.py'
_0xef01.click()
window.URL.revokeObjectURL(_0xdef0)
document["save-button"].bind("click",_0x5678)</script><script>var _0x1234=CodeMirror.fromTextArea(document.getElementById("code"),{mode:"python",theme:"monokai",lineNumbers:!0,autoCloseBrackets:!0,matchBrackets:!0,indentUnit:4,tabSize:4,indentWithTabs:!1,extraKeys:{"Ctrl-Space":"autocomplete","Tab":function(_0x5678){_0x5678.somethingSelected()?_0x5678.indentSelection("add"):_0x5678.replaceSelection(_0x5678.getOption("indentWithTabs")?"\t":Array(_0x5678.getOption("indentUnit")+1).join(" "),"end","+input")}},hintOptions:{completeSingle:!1}});_0x1234.on("inputRead",function(_0x2345,_0x3456){if("+input"===_0x3456.origin){var _0x4567=_0x2345.getCursor(),_0x5678=_0x2345.getTokenAt(_0x4567);("variable"===_0x5678.type||"."===_0x5678.string)&&_0x2345.showHint({completeSingle:!1})}})</script></body></html>