папки с паролями

This commit is contained in:
2026-07-23 04:03:30 +08:00
parent 4d45b78a69
commit a644d3329c
2 changed files with 630 additions and 339 deletions

725
template.html Executable file → Normal file
View File

@@ -1,313 +1,412 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0">
<title>Trashbox</title>
<link rel="shortcut icon" href="/logo.png" type="image/png">
<link rel="stylesheet" href="/cgi-bin/style.cgi">
<meta property="og:image" content="https://home.mashup.su/og.png" />
<meta property="og:image:width" content="600" />
<meta property="og:image:height" content="315" />
<meta property="og:locale" content="ru_RU" />
<meta property="og:type" content="website" />
<meta property="og:title" content="Файлопомойка от RomkaZVO" />
<meta property="og:description" content="Моя личная помоечка" />
<meta property="og:url" content="https://home.mashup.su/" />
<meta property="og:site_name" content="Помойка от RomkaZVO" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Файлопомойка от RomkaZVO" />
<meta name="twitter:description" content="Моя личная помоечка" />
<meta name="twitter:image" content="https://home.mashup.su/og.png" />
<meta name="description" content="Моя личная помоечка" />
<meta name="keywords" content="RomkaZVO, mashup, mashup su, файлы, обмен, скачать, загрузить" />
<script>
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
(function() {
const savedTheme = getCookie('theme');
if (savedTheme === 'dark') {
document.documentElement.classList.add('dark-theme');
}
})();
</script>
</head>
<body>
<button class="theme-toggle" onclick="toggleTheme()">🌙</button>
<div class="container">
<div class="header">
<h1>Trashbox</h1>
<div style="margin-top: 0.5rem; opacity: 0.9; font-size: 1.1rem;">
Моя личная помоечка
</div>
</div>
<div class="content">
<!--BREADCRUMB-->
<!--CONTENT-->
</div>
</div>
<footer class="footer">
<div class="footer-content">
<span>Навайбкодил с любовью ❤️</span>
<a href="https://romkazvo.ru" target="_blank" class="footer-link">RomkaZVO</a><br>
Сделано при помощи BusyBox httpd и Nginx для SSL<br>
Боже, храни Китай партия за DeepSeek
</div>
<div id="status" style="margin-top: 1rem; font-size: 0.8rem; opacity: 0.7; line-height: 1.4;">
Загрузка статистики...
</div>
<script>
fetch('/cgi-bin/status.cgi')
.then(response => response.text())
.then(data => {
document.getElementById('status').innerHTML = data;
})
.catch(err => {
document.getElementById('status').innerHTML = 'Ошибка загрузки статуса';
});
</script>
</footer>
<button class="scroll-top" onclick="scrollToTop()"></button>
<div id="previewModal" class="preview-modal">
<div class="preview-content" id="previewContent">
<div class="preview-header">
<h3 class="preview-title" id="previewTitle">Предпросмотр файла</h3>
<button class="close-preview" onclick="closePreview()">×</button>
</div>
<iframe id="previewFrame" class="preview-iframe" sandbox="allow-scripts allow-same-origin"></iframe>
</div>
</div>
<script>
function scrollToTop() {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
}
window.addEventListener('scroll', function() {
const scrollBtn = document.querySelector('.scroll-top');
if (window.scrollY > 300) {
scrollBtn.classList.add('visible');
} else {
scrollBtn.classList.remove('visible');
}
});
function toggleTheme() {
const isDark = document.body.classList.contains('dark-theme');
const newTheme = isDark ? 'light' : 'dark';
document.body.classList.toggle('dark-theme');
document.documentElement.classList.toggle('dark-theme');
const button = document.querySelector('.theme-toggle');
button.textContent = isDark ? '🌙' : '☀️';
const date = new Date();
date.setFullYear(date.getFullYear() + 1);
document.cookie = `theme=${newTheme}; expires=${date.toUTCString()}; path=/`;
}
function openPreview(fileUrl) {
const modal = document.getElementById('previewModal');
const frame = document.getElementById('previewFrame');
const content = document.getElementById('previewContent');
const title = document.getElementById('previewTitle');
const fileName = fileUrl.split('/').pop();
title.textContent = `Предпросмотр: ${fileName}`;
const fileExt = fileName.split('.').pop().toLowerCase();
const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'svg', 'ico'];
const textTypes = ['txt', 'md', 'html', 'htm', 'css', 'js', 'json', 'xml', 'csv'];
const audioTypes = ['mp3', 'wav', 'ogg', 'flac', 'm4a', 'aac'];
const videoTypes = ['mp4', 'webm', 'ogv', 'mov', 'avi', 'mkv'];
const isPDF = fileExt === 'pdf';
frame.style.display = 'block';
frame.src = '';
let imgContainer = document.getElementById('previewImageContainer');
if (!imgContainer) {
imgContainer = document.createElement('div');
imgContainer.id = 'previewImageContainer';
imgContainer.className = 'preview-image-container';
content.appendChild(imgContainer);
}
imgContainer.style.display = 'none';
imgContainer.innerHTML = '';
if (imageTypes.includes(fileExt)) {
frame.style.display = 'none';
imgContainer.style.display = 'flex';
const img = document.createElement('img');
img.src = fileUrl;
img.alt = fileName;
img.className = 'preview-image';
img.onload = function() {
adjustModalForImage(this);
};
img.onerror = function() {
console.error('Failed to load image:', fileUrl);
frame.style.display = 'block';
imgContainer.style.display = 'none';
frame.src = fileUrl;
};
imgContainer.appendChild(img);
content.style.width = '90vw';
content.style.height = '90vh';
content.style.maxWidth = 'none';
content.style.maxHeight = 'none';
} else {
frame.style.display = 'block';
imgContainer.style.display = 'none';
if (textTypes.includes(fileExt)) {
content.style.width = '80vw';
content.style.height = '70vh';
content.style.maxWidth = '800px';
content.style.maxHeight = '600px';
} else if (audioTypes.includes(fileExt)) {
content.style.width = '500px';
content.style.height = '300px';
content.style.maxWidth = '90vw';
content.style.maxHeight = '400px';
} else if (videoTypes.includes(fileExt)) {
content.style.width = '90vw';
content.style.height = '80vh';
content.style.maxWidth = '1200px';
content.style.maxHeight = '800px';
} else if (isPDF) {
content.style.width = '90vw';
content.style.height = '90vh';
content.style.maxWidth = '1200px';
content.style.maxHeight = '900px';
frame.classList.add('pdf');
} else {
content.style.width = '80vw';
content.style.height = '80vh';
content.style.maxWidth = '1000px';
content.style.maxHeight = '800px';
}
frame.src = fileUrl;
}
modal.style.display = 'block';
document.body.style.overflow = 'hidden';
}
function adjustModalForImage(img) {
const content = document.getElementById('previewContent');
const maxWidth = window.innerWidth * 0.95;
const maxHeight = window.innerHeight * 0.95;
const imgWidth = img.naturalWidth;
const imgHeight = img.naturalHeight;
console.log(`Image size: ${imgWidth}x${imgHeight}, Screen limits: ${maxWidth}x${maxHeight}`);
let scale = 1;
if (imgWidth > maxWidth) {
scale = Math.min(scale, maxWidth / imgWidth);
}
if (imgHeight > maxHeight) {
scale = Math.min(scale, maxHeight / imgHeight);
}
const displayWidth = imgWidth * scale;
const displayHeight = imgHeight * scale;
console.log(`Display size: ${displayWidth}x${displayHeight}, Scale: ${scale}`);
content.style.width = (displayWidth + 20) + 'px';
content.style.height = (displayHeight + 80) + 'px';
content.style.margin = 'auto';
content.style.position = 'absolute';
content.style.left = '50%';
content.style.top = '50%';
content.style.transform = 'translate(-50%, -50%)';
}
function closePreview() {
const modal = document.getElementById('previewModal');
const frame = document.getElementById('previewFrame');
const content = document.getElementById('previewContent');
modal.style.display = 'none';
frame.src = '';
frame.classList.remove('pdf');
content.style.width = '';
content.style.height = '';
content.style.maxWidth = '';
content.style.maxHeight = '';
content.style.margin = '';
content.style.position = '';
content.style.left = '';
content.style.top = '';
content.style.transform = '';
const imgContainer = document.getElementById('previewImageContainer');
if (imgContainer) {
imgContainer.style.display = 'none';
imgContainer.innerHTML = '';
}
document.body.style.overflow = 'auto';
}
document.getElementById('previewModal').addEventListener('click', function(e) {
if (e.target === this) {
closePreview();
}
});
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closePreview();
}
});
document.addEventListener('DOMContentLoaded', function() {
const savedTheme = getCookie('theme');
const button = document.querySelector('.theme-toggle');
if (savedTheme === 'dark') {
document.body.classList.add('dark-theme');
button.textContent = '☀️';
} else {
document.body.classList.remove('dark-theme');
button.textContent = '🌙';
}
document.body.classList.add('loaded');
});
document.addEventListener('touchstart', function() {}, { passive: true });
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0">
<title>Trashbox</title>
<link rel="shortcut icon" href="/logo.png" type="image/png">
<link rel="stylesheet" href="/cgi-bin/style.cgi">
<meta property="og:image" content="https://home.mashup.su/og.png" />
<meta property="og:image:width" content="600" />
<meta property="og:image:height" content="315" />
<meta property="og:locale" content="ru_RU" />
<meta property="og:type" content="website" />
<meta property="og:title" content="Файлопомойка от RomkaZVO" />
<meta property="og:description" content="Моя личная помоечка" />
<meta property="og:url" content="https://home.mashup.su/" />
<meta property="og:site_name" content="Помойка от RomkaZVO" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Файлопомойка от RomkaZVO" />
<meta name="twitter:description" content="Моя личная помоечка" />
<meta name="twitter:image" content="https://home.mashup.su/og.png" />
<meta name="description" content="Моя личная помоечка" />
<meta name="keywords" content="RomkaZVO, mashup, mashup su, файлы, обмен, скачать, загрузить" />
<script>
// Отключаем все alert на странице (на случай, если где-то закрались)
window.alert = function() {
console.log('Alert был заблокирован');
};
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
(function() {
const savedTheme = getCookie('theme');
if (savedTheme === 'dark') {
document.documentElement.classList.add('dark-theme');
}
})();
</script>
</head>
<body>
<button class="theme-toggle" onclick="toggleTheme()">🌙</button>
<div class="container">
<div class="header">
<h1>Trashbox</h1>
<div style="margin-top: 0.5rem; opacity: 0.9; font-size: 1.1rem;">
Моя личная помоечка
</div>
</div>
<div class="content">
<!--BREADCRUMB-->
<!--CONTENT-->
</div>
</div>
<footer class="footer">
<div class="footer-content">
<span>Навайбкодил с любовью ❤️</span>
<a href="https://romkazvo.ru" target="_blank" class="footer-link">RomkaZVO</a><br>
Сделано при помощи BusyBox httpd и Nginx для SSL<br>
Боже, храни Китай партия за DeepSeek
</div>
<div id="status" style="margin-top: 1rem; font-size: 0.8rem; opacity: 0.7; line-height: 1.4;">
Загрузка статистики...
</div>
<script>
fetch('/cgi-bin/status.cgi')
.then(response => response.text())
.then(data => {
document.getElementById('status').innerHTML = data;
})
.catch(err => {
document.getElementById('status').innerHTML = 'Ошибка загрузки статуса';
});
</script>
</footer>
<button class="scroll-top" onclick="scrollToTop()"></button>
<div id="previewModal" class="preview-modal">
<div class="preview-content" id="previewContent">
<div class="preview-header">
<h3 class="preview-title" id="previewTitle">Предпросмотр файла</h3>
<button class="close-preview" onclick="closePreview()">×</button>
</div>
<iframe id="previewFrame" class="preview-iframe" sandbox="allow-scripts allow-same-origin"></iframe>
</div>
</div>
<script>
window.showPasswordForm = function(encodedPath, folderName) {
const modal = document.getElementById('previewModal');
const content = document.getElementById('previewContent');
const title = document.getElementById('previewTitle');
const frame = document.getElementById('previewFrame');
if (!modal || !content || !title || !frame) {
console.error('Modal elements not found!');
return;
}
frame.style.display = 'none';
title.textContent = '🔒 Введите пароль для папки: ' + folderName;
const oldContainer = document.getElementById('passwordFormContainer');
if (oldContainer) {
oldContainer.remove();
}
const container = document.createElement('div');
container.id = 'passwordFormContainer';
container.style.cssText = 'display:flex;justify-content:center;align-items:center;padding:2rem;flex-grow:1;min-height:300px;';
container.innerHTML = `
<div style="background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;padding:2rem;max-width:400px;width:100%;text-align:center;box-shadow:0 4px 20px rgba(0,0,0,0.1);">
<div style="font-size:3rem;margin-bottom:1rem;">🔒</div>
<h2 style="font-size:1.3rem;margin-bottom:0.5rem;color:var(--text-primary);">Защищенная папка</h2>
<p style="color:var(--text-secondary);margin-bottom:1.5rem;font-size:0.95rem;">
Введите пароль для доступа к <strong style="color:var(--text-primary);word-break:break-all;">${folderName}</strong>
</p>
<form method="GET" action="/cgi-bin/index.cgi" onsubmit="return validatePasswordForm(this)">
<input type="hidden" name="path" value="${encodedPath}">
<input type="password" name="password" placeholder="Введите пароль" required style="width:100%;padding:0.75rem 1rem;border:2px solid var(--border-color);border-radius:8px;font-size:1rem;background:var(--bg-primary);color:var(--text-primary);transition:border-color 0.2s ease;box-sizing:border-box;">
<button type="submit" style="width:100%;padding:0.75rem;background:var(--accent-blue);color:white;border:none;border-radius:8px;font-size:1rem;font-weight:600;cursor:pointer;transition:background 0.2s ease;margin-top:0.75rem;">Войти</button>
</form>
<p class="error-msg" style="color:#dc3545;font-size:0.9rem;min-height:1.5rem;margin:0.5rem 0;"></p>
<button onclick="closePreview()" style="background:transparent;border:none;color:var(--text-secondary);cursor:pointer;font-size:0.9rem;margin-top:0.5rem;">✖ Закрыть</button>
</div>
`;
content.appendChild(container);
content.style.width = '500px';
content.style.height = 'auto';
content.style.maxWidth = '90vw';
content.style.maxHeight = 'auto';
content.style.margin = 'auto';
content.style.position = 'absolute';
content.style.left = '50%';
content.style.top = '50%';
content.style.transform = 'translate(-50%, -50%)';
modal.style.display = 'block';
document.body.style.overflow = 'hidden';
setTimeout(() => {
const input = container.querySelector('input[type="password"]');
if (input) input.focus();
}, 100);
};
window.validatePasswordForm = function(form) {
const password = form.querySelector('input[type="password"]').value;
const errorMsg = form.parentElement.querySelector('.error-msg');
if (!password || password.length < 1) {
if (errorMsg) {
errorMsg.textContent = '❌ Пожалуйста, введите пароль';
}
return false;
}
return true;
};
window.scrollToTop = function() {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
};
window.addEventListener('scroll', function() {
const scrollBtn = document.querySelector('.scroll-top');
if (window.scrollY > 300) {
scrollBtn.classList.add('visible');
} else {
scrollBtn.classList.remove('visible');
}
});
window.toggleTheme = function() {
const isDark = document.body.classList.contains('dark-theme');
const newTheme = isDark ? 'light' : 'dark';
document.body.classList.toggle('dark-theme');
document.documentElement.classList.toggle('dark-theme');
const button = document.querySelector('.theme-toggle');
button.textContent = isDark ? '🌙' : '☀️';
const date = new Date();
date.setFullYear(date.getFullYear() + 1);
document.cookie = 'theme=' + newTheme + '; expires=' + date.toUTCString() + '; path=/';
};
window.openPreview = function(fileUrl) {
const modal = document.getElementById('previewModal');
const frame = document.getElementById('previewFrame');
const content = document.getElementById('previewContent');
const title = document.getElementById('previewTitle');
const oldContainer = document.getElementById('passwordFormContainer');
if (oldContainer) {
oldContainer.remove();
}
frame.style.display = 'block';
const fileName = fileUrl.split('/').pop();
title.textContent = 'Предпросмотр: ' + fileName;
const fileExt = fileName.split('.').pop().toLowerCase();
const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'svg', 'ico'];
const textTypes = ['txt', 'md', 'html', 'htm', 'css', 'js', 'json', 'xml', 'csv'];
const audioTypes = ['mp3', 'wav', 'ogg', 'flac', 'm4a', 'aac'];
const videoTypes = ['mp4', 'webm', 'ogv', 'mov', 'avi', 'mkv'];
const isPDF = fileExt === 'pdf';
frame.src = '';
let imgContainer = document.getElementById('previewImageContainer');
if (!imgContainer) {
imgContainer = document.createElement('div');
imgContainer.id = 'previewImageContainer';
imgContainer.className = 'preview-image-container';
content.appendChild(imgContainer);
}
imgContainer.style.display = 'none';
imgContainer.innerHTML = '';
if (imageTypes.includes(fileExt)) {
frame.style.display = 'none';
imgContainer.style.display = 'flex';
const img = document.createElement('img');
img.src = fileUrl;
img.alt = fileName;
img.className = 'preview-image';
img.onload = function() {
adjustModalForImage(this);
};
img.onerror = function() {
console.error('Failed to load image:', fileUrl);
frame.style.display = 'block';
imgContainer.style.display = 'none';
frame.src = fileUrl;
};
imgContainer.appendChild(img);
content.style.width = '90vw';
content.style.height = '90vh';
content.style.maxWidth = 'none';
content.style.maxHeight = 'none';
content.style.margin = '2% auto';
content.style.position = 'relative';
content.style.left = 'auto';
content.style.top = 'auto';
content.style.transform = 'none';
} else {
frame.style.display = 'block';
imgContainer.style.display = 'none';
if (textTypes.includes(fileExt)) {
content.style.width = '80vw';
content.style.height = '70vh';
content.style.maxWidth = '800px';
content.style.maxHeight = '600px';
} else if (audioTypes.includes(fileExt)) {
content.style.width = '500px';
content.style.height = '300px';
content.style.maxWidth = '90vw';
content.style.maxHeight = '400px';
} else if (videoTypes.includes(fileExt)) {
content.style.width = '90vw';
content.style.height = '80vh';
content.style.maxWidth = '1200px';
content.style.maxHeight = '800px';
} else if (isPDF) {
content.style.width = '90vw';
content.style.height = '90vh';
content.style.maxWidth = '1200px';
content.style.maxHeight = '900px';
frame.classList.add('pdf');
} else {
content.style.width = '80vw';
content.style.height = '80vh';
content.style.maxWidth = '1000px';
content.style.maxHeight = '800px';
}
content.style.margin = '2% auto';
content.style.position = 'relative';
content.style.left = 'auto';
content.style.top = 'auto';
content.style.transform = 'none';
frame.src = fileUrl;
}
modal.style.display = 'block';
document.body.style.overflow = 'hidden';
};
window.adjustModalForImage = function(img) {
const content = document.getElementById('previewContent');
const maxWidth = window.innerWidth * 0.95;
const maxHeight = window.innerHeight * 0.95;
const imgWidth = img.naturalWidth;
const imgHeight = img.naturalHeight;
let scale = 1;
if (imgWidth > maxWidth) {
scale = Math.min(scale, maxWidth / imgWidth);
}
if (imgHeight > maxHeight) {
scale = Math.min(scale, maxHeight / imgHeight);
}
const displayWidth = imgWidth * scale;
const displayHeight = imgHeight * scale;
content.style.width = (displayWidth + 20) + 'px';
content.style.height = (displayHeight + 80) + 'px';
content.style.margin = 'auto';
content.style.position = 'absolute';
content.style.left = '50%';
content.style.top = '50%';
content.style.transform = 'translate(-50%, -50%)';
};
window.closePreview = function() {
const modal = document.getElementById('previewModal');
const frame = document.getElementById('previewFrame');
const content = document.getElementById('previewContent');
modal.style.display = 'none';
frame.src = '';
frame.classList.remove('pdf');
frame.style.display = 'block';
const oldContainer = document.getElementById('passwordFormContainer');
if (oldContainer) {
oldContainer.remove();
}
content.style.width = '';
content.style.height = '';
content.style.maxWidth = '';
content.style.maxHeight = '';
content.style.margin = '';
content.style.position = '';
content.style.left = '';
content.style.top = '';
content.style.transform = '';
const imgContainer = document.getElementById('previewImageContainer');
if (imgContainer) {
imgContainer.style.display = 'none';
imgContainer.innerHTML = '';
}
const title = document.getElementById('previewTitle');
title.textContent = 'Предпросмотр файла';
document.body.style.overflow = 'auto';
};
document.getElementById('previewModal').addEventListener('click', function(e) {
if (e.target === this) {
closePreview();
}
});
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closePreview();
}
});
document.addEventListener('DOMContentLoaded', function() {
const savedTheme = getCookie('theme');
const button = document.querySelector('.theme-toggle');
if (savedTheme === 'dark') {
document.body.classList.add('dark-theme');
button.textContent = '☀️';
} else {
document.body.classList.remove('dark-theme');
button.textContent = '🌙';
}
document.body.classList.add('loaded');
});
document.addEventListener('touchstart', function() {}, { passive: true });
</script>
</body>
</html>