ваше сообщение коммита

This commit is contained in:
2026-01-14 21:10:15 +03:00
parent e93b9f3a8f
commit b8b4269fe8
11 changed files with 239 additions and 39 deletions

View File

@@ -45,7 +45,12 @@ async function ensureAdminPagesTable(fields) {
'created_at TIMESTAMP DEFAULT NOW()',
'updated_at TIMESTAMP DEFAULT NOW()',
'show_in_blog BOOLEAN DEFAULT FALSE', // Показывать в блоге
'slug TEXT UNIQUE' // URL-friendly идентификатор для SEO
'slug TEXT UNIQUE', // URL-friendly идентификатор для SEO
'category_id INTEGER', // ID категории
'parent_id INTEGER', // ID родительской страницы
'order_index INTEGER DEFAULT 0', // Порядок сортировки
'nav_path TEXT', // Путь навигации
'is_index_page BOOLEAN DEFAULT FALSE' // Является ли индексной страницей
];
for (const field of fields) {
columns.push(`"${field}_encrypted" TEXT`);
@@ -89,6 +94,41 @@ async function ensureAdminPagesTable(fields) {
}
}
// Добавляем поле category_id если его нет
if (!existingCols.includes('category_id')) {
await db.getQuery()(
`ALTER TABLE ${tableName} ADD COLUMN category_id INTEGER`
);
}
// Добавляем поле parent_id если его нет
if (!existingCols.includes('parent_id')) {
await db.getQuery()(
`ALTER TABLE ${tableName} ADD COLUMN parent_id INTEGER`
);
}
// Добавляем поле order_index если его нет
if (!existingCols.includes('order_index')) {
await db.getQuery()(
`ALTER TABLE ${tableName} ADD COLUMN order_index INTEGER DEFAULT 0`
);
}
// Добавляем поле nav_path если его нет
if (!existingCols.includes('nav_path')) {
await db.getQuery()(
`ALTER TABLE ${tableName} ADD COLUMN nav_path TEXT`
);
}
// Добавляем поле is_index_page если его нет
if (!existingCols.includes('is_index_page')) {
await db.getQuery()(
`ALTER TABLE ${tableName} ADD COLUMN is_index_page BOOLEAN DEFAULT FALSE`
);
}
for (const field of fields) {
const encryptedField = `${field}_encrypted`;
if (!existingCols.includes(encryptedField)) {
@@ -205,9 +245,25 @@ async function generateUniqueSlug(title, pageId, tableName) {
return slug;
}
// Middleware для условной обработки multer (только для multipart/form-data)
const conditionalUpload = (req, res, next) => {
const contentType = req.headers['content-type'] || '';
if (contentType.includes('multipart/form-data')) {
return upload.single('file')(req, res, next);
}
// Для JSON запросов пропускаем multer
next();
};
// Создать страницу (только для админа)
router.post('/', upload.single('file'), async (req, res) => {
router.post('/', conditionalUpload, async (req, res) => {
console.log('[pages] POST /: Начало обработки запроса на создание страницы');
console.log('[pages] POST /: Content-Type:', req.headers['content-type']);
console.log('[pages] POST /: req.body тип:', typeof req.body);
console.log('[pages] POST /: req.body ключи:', req.body ? Object.keys(req.body) : 'req.body пуст');
console.log('[pages] POST /: req.body содержимое:', JSON.stringify(req.body || {}, null, 2).substring(0, 500));
console.log('[pages] POST /: req.file:', req.file ? { name: req.file.originalname, size: req.file.size } : 'нет файла');
try {
if (!req.session || !req.session.authenticated) {
console.log('[pages] POST /: Ошибка аутентификации - сессия не найдена');
@@ -245,6 +301,15 @@ router.post('/', upload.single('file'), async (req, res) => {
// Собираем данные страницы
const bodyRaw = req.body || {};
// Проверяем, что body не пустой
if (!bodyRaw || Object.keys(bodyRaw).length === 0) {
console.error('[pages] POST /: req.body пуст или не определен');
return res.status(400).json({
error: 'Отсутствуют данные страницы',
message: 'Тело запроса пустое. Проверьте Content-Type и формат данных.'
});
}
// Обрабатываем required_permission: если это пустая строка или 'null', устанавливаем null
let requiredPermission = null;
if (bodyRaw.required_permission) {
@@ -2056,7 +2121,7 @@ Disallow: /admin/
Disallow: /content/create
Disallow: /content/edit
Sitemap: ${baseUrl}/api/pages/public/sitemap.xml
Sitemap: ${baseUrl}/sitemap.xml
`;
res.setHeader('Content-Type', 'text/plain');

View File

@@ -89,7 +89,8 @@ DLE is designed for **all types of organizations** that need transparent collect
**All licenses include:**
- Lifetime access to the application
- All future updates free
- All future updates free for 5 years (for token holders)
- **Free setup by contractors within 5 years** (personalization for your business type, integration with business processes, AI assistant configuration, blockchain accounting setup, feature customization if needed)
- Technical support through portal
- AI assistant 24/7 without limits
- Participation in voting for new features
@@ -104,6 +105,7 @@ DLE is designed for **all types of organizations** that need transparent collect
- Pay once
- Access forever
- All updates free for 5 years for license token holders (see [legal/service-terms.md](../legal-en/service-terms.md))
- **Free setup by contractors within 5 years** after license purchase
- No hidden fees
- AI works without request limits
@@ -142,6 +144,7 @@ DLE is designed for **all types of organizations** that need transparent collect
- 🎓 **Online training sessions** (group and individual)
- 📚 **Library of recordings** of all sessions
- 📧 **Email support**
-**Free setup by contractors within 5 years** (personalization, integration, AI configuration, feature customization)
### How does the voting system work?
@@ -734,6 +737,7 @@ Always end with: "How else can I help? 😊"
**All license holders receive**:
- ✅ All web application updates (free for 5 years for token holders)
-**Free setup by contractors within 5 years** (personalization, integration, AI configuration, feature customization)
- ✅ Access to documentation and knowledge base
- ✅ Technical support through application
- ✅ AI assistant 24/7
@@ -803,6 +807,7 @@ You can request refund of **70% of license cost** within **5 years** from purcha
- 🎓 Online training sessions (all licenses)
- 📚 Library of recordings (all licenses)
- 📧 Email support (all licenses)
- ✅ Free setup by contractors within 5 years (all licenses)
**SLA (first response time)**:
- 🔴 Critical: 4 hours
@@ -994,7 +999,7 @@ curl -fsSL https://raw.githubusercontent.com/VC-HB3-Accelerator/DLE/main/setup-t
**One-time costs**:
- License: $1,000-10,000 USDT
- Smart contract deployment: $100-500 (gas fees)
- Setup: $0 (self-service)
- Setup: $0 (free setup by contractors within 5 years included in license)
**Monthly costs**:
- Hosting: $50-200/month

View File

@@ -17,6 +17,7 @@
Key Points:
- License Type: Perpetual, rights determined by number of tokens (1 or 10).
- Updates and Basic Maintenance: Free for 5 years from on-chain token transfer date.
- Free Setup by Contractors: Within 5 years after license purchase (personalization, integration, AI configuration, feature customization).
- Development Voting: 1 token = 1 vote, decisions by majority ≥51%.
- 70% Refund possible if program conditions are met (see original).
- Support, releases, knowledge base — through application `https://hb3-accelerator.com/`.

View File

@@ -89,7 +89,8 @@ DLE создано для **всех типов организаций**, нуж
**Все лицензии включают:**
- Пожизненный доступ к приложению
- Все будущие обновления бесплатно
- Все будущие обновления бесплатно 5 лет (для держателей токенов)
- **Бесплатная настройка подрядчиками в течение 5 лет** (персонализация под ваш вид деятельности, интеграция с бизнес-процессами, настройка ИИ-ассистента, настройка блокчейн-учёта, доработка функционала при необходимости)
- Техническую поддержку через портал
- AI ассистент 24/7 без лимитов
- Участие в голосовании за новые функции
@@ -104,6 +105,7 @@ DLE создано для **всех типов организаций**, нуж
- Оплата один раз
- Доступ навсегда
- Все обновления бесплатно 5 лет для держателей лицензионных токенов (см. [legal/service-terms.md](../legal/service-terms.md))
- **Бесплатная настройка подрядчиками в течение 5 лет** после покупки лицензии
- Никаких скрытых платежей
- AI работает без лимитов на запросы
@@ -142,6 +144,7 @@ DLE создано для **всех типов организаций**, нуж
- 🎓 **Онлайн-сессии обучения** (групповые и индивидуальные)
- 📚 **Библиотека записей** всех сессий
- 📧 **Email поддержка**
-**Бесплатная настройка подрядчиками в течение 5 лет** (персонализация, интеграция, настройка ИИ, доработка функционала)
### Как работает система голосования?
@@ -734,6 +737,7 @@ DLE создано для **всех типов организаций**, нуж
**Все держатели лицензий получают**:
-Все обновления веб-приложения (бесплатно 5 лет для держателей токенов)
-**Бесплатная настройка подрядчиками в течение 5 лет** (персонализация, интеграция, настройка ИИ, доработка функционала)
- ✅ Доступ к документации и базе знаний
- ✅ Техническая поддержка через приложение
- ✅ AI ассистент 24/7
@@ -803,6 +807,7 @@ DLE создано для **всех типов организаций**, нуж
- 🎓 Онлайн-сессии обучения (все лицензии)
- 📚 Библиотека записей (все лицензии)
- 📧 Email поддержка (все лицензии)
- ✅ Бесплатная настройка подрядчиками в течение 5 лет (все лицензии)
**SLA (время первого ответа)**:
- 🔴 Критическая: 4 часа
@@ -994,7 +999,7 @@ curl -fsSL https://raw.githubusercontent.com/VC-HB3-Accelerator/DLE/main/setup-t
**Единоразовые расходы**:
- Лицензия: $1,000-10,000 USDT
- Деплой смарт-контракта: $100-500 (gas fees)
- Настройка: $0 (самостоятельно)
- Настройка: $0 (бесплатная настройка подрядчиками в течение 5 лет включена в лицензию)
**Ежемесячные расходы**:
- Хостинг: $50-200/месяц

View File

@@ -17,6 +17,7 @@
Ключевые тезисы:
- Тип лицензии: бессрочная (Perpetual), права определяются количеством токенов (1 или 10).
- Обновления и базовое обслуживание: бесплатно 5 лет с даты on-chain передачи токена.
- Бесплатная настройка подрядчиками: в течение 5 лет после покупки лицензии (персонализация, интеграция, настройка ИИ, доработка функционала).
- Голосование за развитие: 1 токен = 1 голос, решения большинством ≥51%.
- Возврат 70% возможен при соблюдении условий программы (см. оригинал).
- Поддержка, релизы, база знаний — через приложение `https://hb3-accelerator.com/`.

View File

@@ -28,6 +28,25 @@ http {
add_header Content-Type text/plain;
}
# Разрешаем доступ к robots.txt и sitemap.xml для поисковых систем
location = /robots.txt {
proxy_pass http://${BACKEND_CONTAINER}:8000/api/pages/public/robots.txt;
proxy_set_header Host $host;
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;
add_header Content-Type text/plain;
}
location = /sitemap.xml {
proxy_pass http://${BACKEND_CONTAINER}:8000/api/pages/public/sitemap.xml;
proxy_set_header Host $host;
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;
add_header Content-Type application/xml;
}
# Основной location
location / {
# Rate limiting для основных страниц (отключено)

View File

@@ -13,13 +13,21 @@ http {
# limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s;
# limit_req_zone $binary_remote_addr zone=api_limit_per_ip:10m rate=5r/s;
# Блокировка известных сканеров и вредоносных ботов
# Блокировка известных сканеров и вредоносных ботов (исключая легитимные поисковые боты)
map $http_user_agent $bad_bot {
default 0;
~*bot 1;
~*crawler 1;
~*spider 1;
~*scanner 1;
# Разрешаем легитимные поисковые боты
~*googlebot 0;
~*bingbot 0;
~*slurp 0;
~*duckduckbot 0;
~*baiduspider 0;
~*yandex 0;
~*sogou 0;
~*exabot 0;
~*facebot 0;
~*ia_archiver 0;
# Блокируем вредоносные боты и сканеры
~*sqlmap 1;
~*nikto 1;
~*dirb 1;
@@ -29,6 +37,9 @@ http {
~*zap 1;
~*nessus 1;
~*openvas 1;
~*masscan 1;
~*nmap 1;
~*scanner 1;
~*Chrome/[1-4][0-9]\. 1;
~*Firefox/[1-6][0-9]\. 1;
~*Safari/[1-9]\. 1;

View File

@@ -37,13 +37,21 @@ function getNginxConfig(domain, serverPort) {
# limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s;
# limit_req_zone $binary_remote_addr zone=api_limit_per_ip:10m rate=50r/s;
# Блокировка известных сканеров и вредоносных ботов
# Блокировка известных сканеров и вредоносных ботов (исключая легитимные поисковые боты)
map $http_user_agent $bad_bot {
default 0;
~*bot 1;
~*crawler 1;
~*spider 1;
~*scanner 1;
# Разрешаем легитимные поисковые боты
~*googlebot 0;
~*bingbot 0;
~*slurp 0;
~*duckduckbot 0;
~*baiduspider 0;
~*yandex 0;
~*sogou 0;
~*exabot 0;
~*facebot 0;
~*ia_archiver 0;
# Блокируем вредоносные боты и сканеры
~*sqlmap 1;
~*nikto 1;
~*dirb 1;
@@ -53,6 +61,9 @@ map $http_user_agent $bad_bot {
~*zap 1;
~*nessus 1;
~*openvas 1;
~*masscan 1;
~*nmap 1;
~*scanner 1;
}
server {
@@ -74,12 +85,31 @@ server {
return 404;
}
# Защита от доступа к чувствительным файлам
location ~* /(\\\\.htaccess|\\\\.htpasswd|\\\\.env|\\\\.git|\\\\.svn|\\\\.DS_Store|Thumbs\\\\.db|web\\\\.config|robots\\\\.txt|sitemap\\\\.xml)$ {
# Защита от доступа к чувствительным файлам (исключаем robots.txt и sitemap.xml для SEO)
location ~* /(\\\\.htaccess|\\\\.htpasswd|\\\\.env|\\\\.git|\\\\.svn|\\\\.DS_Store|Thumbs\\\\.db|web\\\\.config)$ {
deny all;
return 404;
}
# Разрешаем доступ к robots.txt и sitemap.xml для поисковых систем
location = /robots.txt {
proxy_pass http://localhost:8000/api/pages/public/robots.txt;
proxy_set_header Host $host;
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;
add_header Content-Type text/plain;
}
location = /sitemap.xml {
proxy_pass http://localhost:8000/api/pages/public/sitemap.xml;
proxy_set_header Host $host;
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;
add_header Content-Type application/xml;
}
# Основной location для фронтенда
location / {
# Rate limiting для основных страниц (отключено)
@@ -476,13 +506,21 @@ app.post('/tunnel/create', async (req, res) => {
# limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s;
# limit_req_zone $binary_remote_addr zone=api_limit_per_ip:10m rate=50r/s;
# Блокировка известных сканеров и вредоносных ботов
# Блокировка известных сканеров и вредоносных ботов (исключая легитимные поисковые боты)
map $http_user_agent $bad_bot {
default 0;
~*bot 1;
~*crawler 1;
~*spider 1;
~*scanner 1;
# Разрешаем легитимные поисковые боты
~*googlebot 0;
~*bingbot 0;
~*slurp 0;
~*duckduckbot 0;
~*baiduspider 0;
~*yandex 0;
~*sogou 0;
~*exabot 0;
~*facebot 0;
~*ia_archiver 0;
# Блокируем вредоносные боты и сканеры
~*sqlmap 1;
~*nikto 1;
~*dirb 1;
@@ -492,6 +530,9 @@ map $http_user_agent $bad_bot {
~*zap 1;
~*nessus 1;
~*openvas 1;
~*masscan 1;
~*nmap 1;
~*scanner 1;
}
server {
@@ -513,12 +554,31 @@ server {
return 404;
}
# Защита от доступа к чувствительным файлам
location ~* /(\\\\.htaccess|\\\\.htpasswd|\\\\.env|\\\\.git|\\\\.svn|\\\\.DS_Store|Thumbs\\\\.db|web\\\\.config|robots\\\\.txt|sitemap\\\\.xml)$ {
# Защита от доступа к чувствительным файлам (исключаем robots.txt и sitemap.xml для SEO)
location ~* /(\\\\.htaccess|\\\\.htpasswd|\\\\.env|\\\\.git|\\\\.svn|\\\\.DS_Store|Thumbs\\\\.db|web\\\\.config)$ {
deny all;
return 404;
}
# Разрешаем доступ к robots.txt и sitemap.xml для поисковых систем
location = /robots.txt {
proxy_pass http://localhost:8000/api/pages/public/robots.txt;
proxy_set_header Host $host;
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;
add_header Content-Type text/plain;
}
location = /sitemap.xml {
proxy_pass http://localhost:8000/api/pages/public/sitemap.xml;
proxy_set_header Host $host;
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;
add_header Content-Type application/xml;
}
# Основной location для фронтенда
location / {
# Rate limiting для основных страниц (отключено)

View File

@@ -190,3 +190,4 @@ onMounted(async () => {
}
</style>

View File

@@ -10,13 +10,15 @@ NC='\033[0m' # No Color
echo -e "${GREEN}🔄 Синхронизация кода с VDS...${NC}"
# Параметры VDS (из настроек)
VDS_HOST="185.26.121.127"
VDS_HOST="185.221.214.140"
VDS_USER="root"
VDS_PORT="22"
VDS_PATH="/home/docker/dapp"
# SSH опции
SSH_OPTS="-p $VDS_PORT -o StrictHostKeyChecking=no"
# SCP опции (scp использует -P для порта, а не -p)
SCP_OPTS="-P $VDS_PORT -o StrictHostKeyChecking=no"
# Проверяем наличие rsync на удаленном сервере
echo -e "${YELLOW}🔍 Проверка наличия rsync на VDS...${NC}"
@@ -94,7 +96,7 @@ sync_with_tar() {
-C "$(dirname "$SRC_DIR")" "$DIR_NAME"
# Копируем архив на VDS
scp -e "ssh $SSH_OPTS" "$TMP_TAR" "$VDS_USER@$VDS_HOST:/tmp/"
scp $SCP_OPTS "$TMP_TAR" "$VDS_USER@$VDS_HOST:/tmp/"
# Распаковываем на VDS
ssh $SSH_OPTS $VDS_USER@$VDS_HOST "mkdir -p $DST_DIR && tar -xzf /tmp/$(basename $TMP_TAR) -C $DST_DIR --strip-components=1 && rm /tmp/$(basename $TMP_TAR)"
@@ -129,13 +131,13 @@ fi
# Синхронизация docker-compose.prod.yml
echo -e "${YELLOW}📦 Синхронизация docker-compose.prod.yml...${NC}"
scp -e "ssh $SSH_OPTS" ./webssh-agent/docker-compose.prod.yml "$VDS_USER@$VDS_HOST:$VDS_PATH/docker-compose.prod.yml"
scp $SCP_OPTS ./webssh-agent/docker-compose.prod.yml "$VDS_USER@$VDS_HOST:$VDS_PATH/docker-compose.prod.yml"
# Синхронизация Dockerfile файлов (если они изменились)
echo -e "${YELLOW}📦 Синхронизация Dockerfile файлов...${NC}"
scp -e "ssh $SSH_OPTS" ./backend/Dockerfile "$VDS_USER@$VDS_HOST:$VDS_PATH/backend/Dockerfile" 2>/dev/null || true
scp -e "ssh $SSH_OPTS" ./frontend/Dockerfile "$VDS_USER@$VDS_HOST:$VDS_PATH/frontend/Dockerfile" 2>/dev/null || true
scp -e "ssh $SSH_OPTS" ./frontend/nginx.Dockerfile "$VDS_USER@$VDS_HOST:$VDS_PATH/frontend/nginx.Dockerfile" 2>/dev/null || true
scp $SCP_OPTS ./backend/Dockerfile "$VDS_USER@$VDS_HOST:$VDS_PATH/backend/Dockerfile" 2>/dev/null || true
scp $SCP_OPTS ./frontend/Dockerfile "$VDS_USER@$VDS_HOST:$VDS_PATH/frontend/Dockerfile" 2>/dev/null || true
scp $SCP_OPTS ./frontend/nginx.Dockerfile "$VDS_USER@$VDS_HOST:$VDS_PATH/frontend/nginx.Dockerfile" 2>/dev/null || true
echo -e "${GREEN}✅ Синхронизация завершена!${NC}"

View File

@@ -10,13 +10,21 @@ http {
limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=api_limit_per_ip:10m rate=5r/s;
# Блокировка известных сканеров и вредоносных ботов
# Блокировка известных сканеров и вредоносных ботов (исключая легитимные поисковые боты)
map $http_user_agent $bad_bot {
default 0;
~*bot 1;
~*crawler 1;
~*spider 1;
~*scanner 1;
# Разрешаем легитимные поисковые боты
~*googlebot 0;
~*bingbot 0;
~*slurp 0;
~*duckduckbot 0;
~*baiduspider 0;
~*yandex 0;
~*sogou 0;
~*exabot 0;
~*facebot 0;
~*ia_archiver 0;
# Блокируем вредоносные боты и сканеры
~*sqlmap 1;
~*nikto 1;
~*dirb 1;
@@ -26,6 +34,9 @@ http {
~*zap 1;
~*nessus 1;
~*openvas 1;
~*masscan 1;
~*nmap 1;
~*scanner 1;
~*Chrome/[1-4][0-9]\. 1;
~*Firefox/[1-6][0-9]\. 1;
~*Safari/[1-9]\. 1;
@@ -54,12 +65,31 @@ http {
return 404;
}
# Защита от доступа к чувствительным файлам
location ~* /(\.htaccess|\.htpasswd|\.env|\.git|\.svn|\.DS_Store|Thumbs\.db|web\.config|robots\.txt|sitemap\.xml)$ {
# Защита от доступа к чувствительным файлам (исключаем robots.txt и sitemap.xml для SEO)
location ~* /(\.htaccess|\.htpasswd|\.env|\.git|\.svn|\.DS_Store|Thumbs\.db|web\.config)$ {
deny all;
return 404;
}
# Разрешаем доступ к robots.txt и sitemap.xml для поисковых систем
location = /robots.txt {
proxy_pass http://BACKEND_CONTAINER_PLACEHOLDER:8000/api/pages/public/robots.txt;
proxy_set_header Host $host;
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;
add_header Content-Type text/plain;
}
location = /sitemap.xml {
proxy_pass http://BACKEND_CONTAINER_PLACEHOLDER:8000/api/pages/public/sitemap.xml;
proxy_set_header Host $host;
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;
add_header Content-Type application/xml;
}
# Защита от доступа к конфигурационным файлам
location ~* /\.(env|config|ini|conf|cfg|yml|yaml|json|xml|sql|db|bak|backup|old|tmp|temp|log)$ {
deny all;