feat: новая функция

This commit is contained in:
2025-10-24 23:53:16 +03:00
parent 1a9be1d4c0
commit 2708a7c1d3
29 changed files with 2668 additions and 487 deletions

View File

@@ -1,130 +0,0 @@
# 🚀 Экспорт шаблона приложения в GitHub
## Цель
Экспортировать все образы и тома как файлы в GitHub репозиторий для создания полного шаблона приложения.
## 📋 Команды для экспорта
### 1. Создать папки для данных
```bash
mkdir -p ./docker-data/images
mkdir -p ./docker-data/volumes
```
### 2. Экспортировать образы в файлы
```bash
# Backend образ
docker save digital_legal_entitydle-backend:latest -o ./docker-data/images/backend.tar
# Frontend образ
docker save digital_legal_entitydle-frontend:latest -o ./docker-data/images/frontend.tar
# Vector Search образ
docker save digital_legal_entitydle-vector-search:latest -o ./docker-data/images/vector-search.tar
# Ollama образ
docker save digital_legal_entitydle-ollama:latest -o ./docker-data/images/ollama.tar
# WebSSH Agent образ
docker save digital_legal_entitydle-webssh-agent:latest -o ./docker-data/images/webssh-agent.tar
```
### 3. Экспортировать тома в файлы
```bash
# PostgreSQL данные
docker run --rm -v digital_legal_entitydle_postgres_data:/source -v $(pwd)/docker-data/volumes:/backup alpine tar czf /backup/postgres_data.tar.gz -C /source .
# Ollama данные
docker run --rm -v digital_legal_entitydle_ollama_data:/source -v $(pwd)/docker-data/volumes:/backup alpine tar czf /backup/ollama_data.tar.gz -C /source .
# Vector Search данные
docker run --rm -v digital_legal_entitydle_vector_search_data:/source -v $(pwd)/docker-data/volumes:/backup alpine tar czf /backup/vector_search_data.tar.gz -C /source .
# Backend node_modules
docker run --rm -v digital_legal_entitydle_backend_node_modules:/source -v $(pwd)/docker-data/volumes:/backup alpine tar czf /backup/backend_node_modules.tar.gz -C /source .
# Frontend node_modules
docker run --rm -v digital_legal_entitydle_frontend_node_modules:/source -v $(pwd)/docker-data/volumes:/backup alpine tar czf /backup/frontend_node_modules.tar.gz -C /source .
```
### 4. Загрузить все в GitHub
```bash
# Добавить файлы в git
git add docker-data/
# Закоммитить
git commit -m "Add exported images and volumes"
# Запушить в репозиторий
git push
```
## 📊 Результат
После выполнения всех команд в репозитории будут:
-Все образы как файлы (.tar)
-Все тома как файлы (.tar.gz)
- ✅ Полный шаблон приложения
## 🚀 Использование шаблона
### Для пользователей:
```bash
# Клонировать репозиторий
git clone https://github.com/VC-HB3-Accelerator/DLE.git
cd DLE
# Импортировать образы
docker load -i docker-data/images/backend.tar
docker load -i docker-data/images/frontend.tar
docker load -i docker-data/images/vector-search.tar
docker load -i docker-data/images/ollama.tar
docker load -i docker-data/images/webssh-agent.tar
# Импортировать тома
docker volume create digital_legal_entitydle_postgres_data
docker run --rm -v digital_legal_entitydle_postgres_data:/target -v $(pwd)/docker-data/volumes:/backup alpine tar xzf /backup/postgres_data.tar.gz -C /target
docker volume create digital_legal_entitydle_ollama_data
docker run --rm -v digital_legal_entitydle_ollama_data:/target -v $(pwd)/docker-data/volumes:/backup alpine tar xzf /backup/ollama_data.tar.gz -C /target
docker volume create digital_legal_entitydle_vector_search_data
docker run --rm -v digital_legal_entitydle_vector_search_data:/target -v $(pwd)/docker-data/volumes:/backup alpine tar xzf /backup/vector_search_data.tar.gz -C /target
docker volume create digital_legal_entitydle_backend_node_modules
docker run --rm -v digital_legal_entitydle_backend_node_modules:/target -v $(pwd)/docker-data/volumes:/backup alpine tar xzf /backup/backend_node_modules.tar.gz -C /target
docker volume create digital_legal_entitydle_frontend_node_modules
docker run --rm -v digital_legal_entitydle_frontend_node_modules:/target -v $(pwd)/docker-data/volumes:/backup alpine tar xzf /backup/frontend_node_modules.tar.gz -C /target
# Запустить приложение
docker-compose up -d
```
## ⚠️ Важные замечания
1. **Размер файлов**: Образы могут быть большими (несколько GB)
2. **Время загрузки**: Зависит от размера файлов и скорости интернета
3. **Место на диске**: Убедитесь, что достаточно места для всех файлов
## 📁 Структура после экспорта
```
docker-data/
├── images/
│ ├── backend.tar
│ ├── frontend.tar
│ ├── vector-search.tar
│ ├── ollama.tar
│ └── webssh-agent.tar
└── volumes/
├── postgres_data.tar.gz
├── ollama_data.tar.gz
├── vector_search_data.tar.gz
├── backend_node_modules.tar.gz
└── frontend_node_modules.tar.gz
```
## ✅ Готово!
После выполнения всех команд у вас будет полный шаблон приложения в GitHub репозитории, который можно клонировать и запускать на любом устройстве.

View File

@@ -44,18 +44,55 @@ docker-compose up -d
```
### Доступ к приложению
#### Разработка (dev)
- **Frontend**: http://localhost:5173
- **Backend API**: http://localhost:8000
#### Продакшн (production)
- **Frontend**: http://localhost:9000 (HTTP) или https://localhost:9443 (HTTPS)
- **Backend API**: http://localhost:9000/api (через nginx proxy)
## 🔧 Управление
### Запуск
```
#### Продакшн (production)
```bash
docker-compose up -d
# Пересборка образов
docker-compose build --no-cache
# Запуск продакшн-сервисов
NODE_ENV=production docker-compose --profile production up -d
# Проверка
docker-compose ps
curl http://localhost:9000/api/health
```
### Остановка
```bash
docker-compose down
docker-compose-down
```
### Полезные команды
```bash
# Просмотр логов
docker-compose logs -f backend
docker-compose logs -f frontend-nginx
# Перезапуск сервиса
docker-compose restart backend
docker-compose restart frontend-nginx
# Пересборка конкретного сервиса
docker-compose build --no-cache backend
docker-compose build --no-cache frontend-nginx
# Просмотр статуса
docker-compose ps
docker ps # Все контейнеры в системе
```
## 📝 Лицензия

View File

@@ -22,8 +22,7 @@ README*
.git/
.gitignore
# Зависимости (будут установлены в контейнере)
node_modules/
# Логи установки
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@@ -16,6 +16,7 @@ const cors = require('cors');
const session = require('express-session');
const sessionConfig = require('./config/session');
const logger = require('./utils/logger');
const rateLimit = require('express-rate-limit');
// const csurf = require('csurf'); // Закомментировано, так как не используется
const errorHandler = require('./middleware/errorHandler');
// const { version } = require('./package.json'); // Закомментировано, так как не используется
@@ -115,14 +116,21 @@ app.set('host', '0.0.0.0');
app.set('port', process.env.PORT || 8000);
// Настройка CORS
const corsOrigins = process.env.NODE_ENV === 'production'
? [
'http://localhost:9000', // Локальный Docker nginx
'https://localhost:9443', // Локальный Docker nginx HTTPS
// Добавьте ваш продакшн домен здесь для VDS
// 'https://yourdomain.com',
]
: [
'http://localhost:5173', // Vite dev server
'http://127.0.0.1:5173',
];
app.use(
cors({
origin: [
'http://localhost:5173',
'http://127.0.0.1:5173',
'https://hb3-accelerator.com',
'https://www.hb3-accelerator.com',
],
origin: corsOrigins,
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'Cookie'],
@@ -171,6 +179,36 @@ app.use((req, res, next) => {
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Определяем режим работы
const isProduction = process.env.NODE_ENV === 'production';
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 минут
max: isProduction ? 100 : 1000, // 100 запросов в продакшне, 1000 в dev
message: {
error: 'Слишком много запросов, попробуйте позже',
retryAfter: '15 минут'
},
standardHeaders: true,
legacyHeaders: false,
});
// Применяем rate limiting ко всем запросам
app.use(limiter);
// Строгий rate limiting для чувствительных эндпоинтов
const strictLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 минут
max: 10, // 10 попыток
message: {
error: 'Превышен лимит попыток, попробуйте позже',
retryAfter: '15 минут'
},
standardHeaders: true,
legacyHeaders: false,
});
// Статическая раздача загруженных файлов (для dev и prod)
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));
app.use('/api/uploads', express.static(path.join(__dirname, 'uploads')));
@@ -178,14 +216,26 @@ app.use('/api/uploads', express.static(path.join(__dirname, 'uploads')));
// Настройка безопасности
app.use(
helmet({
contentSecurityPolicy: false, // Отключаем CSP для разработки
contentSecurityPolicy: isProduction ? {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'", "ws:", "wss:"],
fontSrc: ["'self'"],
objectSrc: ["'none'"],
mediaSrc: ["'self'"],
frameSrc: ["'none'"],
},
} : false, // Отключаем CSP для разработки
})
);
// Маршруты API
app.use('/api/tables', tablesRoutes); // ДОЛЖНО БЫТЬ ВЫШЕ!
// app.use('/api', identitiesRoutes);
app.use('/api/auth', authRoutes);
app.use('/api/auth', strictLimiter, authRoutes); // Строгий rate limiting для аутентификации
app.use('/api/users', usersRoutes);
app.use('/api/chat', chatRoutes);
app.use('/api/admin', adminRoutes);
@@ -195,10 +245,10 @@ app.use('/api/kpp', kppRoutes); // Добавленное использован
app.use('/api/geocoding', geocodingRoutes); // Добавленное использование роута
app.use('/api/dle-v2', dleV2Routes); // Добавляем маршрут DLE v2
app.use('/api/settings', settingsRoutes); // Добавляем маршрут настроек
app.use('/api/settings', strictLimiter, settingsRoutes); // Строгий rate limiting для настроек
app.use('/api/countries', countriesRoutes); // Добавляем маршрут стран
app.use('/api/russian-classifiers', russianClassifiersRoutes); // Добавляем маршрут российских классификаторов
app.use('/api/ollama', ollamaRoutes); // Добавляем маршрут Ollama
app.use('/api/ollama', strictLimiter, ollamaRoutes); // Строгий rate limiting для Ollama
app.use('/api/ai-queue', aiQueueRoutes); // Добавляем маршрут AI Queue
app.use('/api/tags', tagsRoutes); // Добавляем маршрут тегов
app.use('/api/blockchain', blockchainRoutes); // Добавляем маршрут blockchain

View File

@@ -24,6 +24,8 @@ function setPoolChangeCallback(cb) {
let sessionMiddleware = createSessionMiddleware();
function createSessionMiddleware() {
const isProduction = process.env.NODE_ENV === 'production';
return session({
store: new pgSession({
pool: db.getPool(),
@@ -36,8 +38,8 @@ function createSessionMiddleware() {
cookie: {
maxAge: 30 * 24 * 60 * 60 * 1000,
httpOnly: true,
secure: false,
sameSite: 'lax',
secure: false, // false для локального Docker (HTTP)
sameSite: 'lax', // lax для локального Docker
path: '/',
},
});

View File

@@ -787,21 +787,25 @@ router.get('/encryption-key/status', requireAdmin, async (req, res) => {
const exists = fs.existsSync(keyPath);
let key = null;
if (exists) {
try {
key = fs.readFileSync(keyPath, 'utf8').trim();
} catch (error) {
logger.error('Ошибка чтения ключа:', error);
}
// Возвращаем только метаданные без содержимого ключа
let checksum = null;
if (exists) {
try {
const data = fs.readFileSync(keyPath);
// лёгкая хэш-сумма для проверки целостности без раскрытия ключа
const crypto = require('crypto');
checksum = crypto.createHash('sha256').update(data).digest('hex');
} catch (error) {
logger.error('Ошибка чтения ключа для метаданных:', error);
}
res.json({
success: true,
exists,
path: keyPath,
key: key
});
}
res.json({
success: true,
exists,
path: keyPath,
checksum
});
} catch (error) {
logger.error('Ошибка проверки статуса ключа шифрования:', error);
res.status(500).json({ success: false, error: error.message });

View File

@@ -1,48 +1,10 @@
const express = require('express');
const router = express.Router();
const fs = require('fs');
const path = require('path');
const https = require('https');
const { promisify } = require('util');
const dns = require('dns');
const resolve4 = promisify(dns.resolve4);
const SSH_DIR = path.join(process.env.HOME || process.env.USERPROFILE, '.ssh');
const DEFAULT_KEY_PATH = path.join(SSH_DIR, 'id_rsa');
const DEFAULT_PUB_KEY_PATH = path.join(SSH_DIR, 'id_rsa.pub');
// Helper to read SSH key
const readSshKey = (keyPath) => {
try {
return fs.readFileSync(keyPath, 'utf8');
} catch (error) {
return null;
}
};
// GET /api/ssh-key - Get existing SSH private key
router.get('/ssh-key', (req, res) => {
const privateKey = readSshKey(DEFAULT_KEY_PATH);
const publicKey = readSshKey(DEFAULT_PUB_KEY_PATH);
if (privateKey) {
res.json({ success: true, sshKey: privateKey, publicKey: publicKey, keyType: 'rsa' });
} else {
res.status(404).json({ success: false, message: 'SSH private key not found' });
}
});
// GET /api/ssh-key/public - Get existing SSH public key
router.get('/ssh-key/public', (req, res) => {
const publicKey = readSshKey(DEFAULT_PUB_KEY_PATH);
if (publicKey) {
res.json({ success: true, publicKey: publicKey, keyType: 'rsa' });
} else {
res.status(404).json({ success: false, message: 'SSH public key not found' });
}
});
// Удалено: эндпоинты выдачи приватного/публичного SSH-ключа
// GET /api/dns-check/:domain - Check DNS and get IP address
router.get('/dns-check/:domain', async (req, res) => {

View File

@@ -0,0 +1,279 @@
/**
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
* All rights reserved.
*
* This software is proprietary and confidential.
* Unauthorized copying, modification, or distribution is prohibited.
*
* For licensing inquiries: info@hb3-accelerator.com
* Website: https://hb3-accelerator.com
* GitHub: https://github.com/HB3-ACCELERATOR
*/
/**
* Единая матрица прав доступа для DLE
* Используется и на backend, и на frontend
*/
// Роли в системе
const ROLES = {
GUEST: 'guest', // Неавторизованный гость
USER: 'user', // Авторизованный гость (0 токенов)
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
EDITOR: 'editor' // Админ редактор (токены >= X)
};
// Список всех прав в системе
const PERMISSIONS = {
// Публичный доступ
VIEW_HOME: 'view_home',
CHAT_AI: 'chat_ai',
// Получение сообщений
RECEIVE_MESSAGES: 'receive_messages',
// Просмотр данных
VIEW_CRM: 'view_crm',
VIEW_CONTACTS: 'view_contacts',
VIEW_DATA: 'view_data',
// Отправка сообщений
SEND_TO_USERS: 'send_to_users',
CHAT_WITH_ADMINS: 'chat_with_admins',
// AI функции
GENERATE_AI_REPLIES: 'generate_ai_replies',
// Редактирование
EDIT_USER_DATA: 'edit_user_data',
EDIT_CONTACTS: 'edit_contacts',
// Удаление
DELETE_USER_DATA: 'delete_user_data',
DELETE_MESSAGES: 'delete_messages',
// Массовые операции
BROADCAST: 'broadcast',
// Управление тегами
MANAGE_TAGS: 'manage_tags',
// Блокировка пользователей
BLOCK_USERS: 'block_users',
// Управление настройками
MANAGE_SETTINGS: 'manage_settings',
// Контент: юридические документы
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
};
// Матрица: какая роль имеет какие права
const PERMISSIONS_MAP = {
[ROLES.GUEST]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI
],
[ROLES.USER]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
],
[ROLES.READONLY]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Чтение внутренних юридических документов
PERMISSIONS.VIEW_LEGAL_DOCS
],
[ROLES.EDITOR]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
PERMISSIONS.GENERATE_AI_REPLIES,
PERMISSIONS.EDIT_USER_DATA,
PERMISSIONS.EDIT_CONTACTS,
PERMISSIONS.DELETE_USER_DATA,
PERMISSIONS.DELETE_MESSAGES,
PERMISSIONS.BROADCAST,
PERMISSIONS.MANAGE_TAGS,
PERMISSIONS.BLOCK_USERS,
PERMISSIONS.MANAGE_SETTINGS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Полный доступ к юридическим документам
PERMISSIONS.VIEW_LEGAL_DOCS,
PERMISSIONS.MANAGE_LEGAL_DOCS
]
};
/**
* Проверяет, имеет ли роль определенное право
* @param {string} role - Роль пользователя
* @param {string} permission - Требуемое право
* @returns {boolean}
*/
function hasPermission(role, permission) {
if (!role || !permission) return false;
return PERMISSIONS_MAP[role]?.includes(permission) || false;
}
/**
* Получает все права для роли
* @param {string} role - Роль пользователя
* @returns {Array<string>}
*/
function getPermissionsForRole(role) {
return PERMISSIONS_MAP[role] || [];
}
/**
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAnyPermission(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.some(p => hasPermission(role, p));
}
/**
* Проверяет, имеет ли роль ВСЕ указанные права
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAllPermissions(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.every(p => hasPermission(role, p));
}
/**
* Получает описание роли
* @param {string} role - Роль пользователя
* @returns {string}
*/
function getRoleDescription(role) {
const descriptions = {
[ROLES.GUEST]: 'Неавторизованный гость',
[ROLES.USER]: 'Авторизованный гость',
[ROLES.READONLY]: 'Админ (только чтение)',
[ROLES.EDITOR]: 'Админ (редактор)'
};
return descriptions[role] || 'Неизвестная роль';
}
/**
* Проверить, может ли отправитель отправлять сообщения получателю
* @param {string} senderRole - Роль отправителя
* @param {string} recipientRole - Роль получателя
* @param {number} senderId - ID отправителя
* @param {number} recipientId - ID получателя
* @returns {Object} { canSend: boolean, errorMessage?: string }
*/
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
// Проверяем базовое право на отправку сообщений
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
return {
canSend: false,
errorMessage: 'У вас нет права на отправку сообщений'
};
}
// Собственный чат - всегда разрешен (для ИИ ассистента)
if (senderId === recipientId) {
return { canSend: true };
}
// USER и READONLY могут писать только EDITOR
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
return { canSend: true };
}
// EDITOR может писать всем (USER, READONLY, EDITOR)
if (senderRole === 'editor') {
return { canSend: true };
}
// USER и READONLY НЕ могут писать друг другу
if ((senderRole === 'user' || senderRole === 'readonly') &&
(recipientRole === 'user' || recipientRole === 'readonly')) {
return {
canSend: false,
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
};
}
// Остальные случаи запрещены
return {
canSend: false,
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
};
}
// Экспорты для CommonJS (Node.js)
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}
// ES модули для Frontend
export {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
// CommonJS для Backend
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}

View File

@@ -1,248 +0,0 @@
# Проверка схемы базы данных
## Таблица `users`
```sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(255),
email VARCHAR(255) UNIQUE,
address VARCHAR(255) UNIQUE,
first_name_encrypted TEXT,
last_name_encrypted TEXT,
status VARCHAR(50) DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
role user_role DEFAULT 'user',
first_name VARCHAR(255),
last_name VARCHAR(255),
preferred_language JSONB,
is_blocked BOOLEAN DEFAULT false,
blocked_at TIMESTAMP
);
```
**Колонки:**
- `id` - SERIAL PRIMARY KEY
- `username` - VARCHAR(255)
- `email` - VARCHAR(255) UNIQUE
- `address` - VARCHAR(255) UNIQUE
- `first_name_encrypted` - TEXT (зашифрованное)
- `last_name_encrypted` - TEXT (зашифрованное)
- `status` - VARCHAR(50) DEFAULT 'active'
- `created_at` - TIMESTAMP DEFAULT CURRENT_TIMESTAMP
- `updated_at` - TIMESTAMP DEFAULT CURRENT_TIMESTAMP
- `role` - user_role DEFAULT 'user'
- `first_name` - VARCHAR(255) (незашифрованное)
- `last_name` - VARCHAR(255) (незашифрованное)
- `preferred_language` - JSONB
- `is_blocked` - BOOLEAN DEFAULT false
- `blocked_at` - TIMESTAMP
## Таблица `conversations`
```sql
CREATE TABLE conversations (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
title VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
conversation_type VARCHAR(50) DEFAULT 'user_chat'
);
```
**Колонки:**
- `id` - SERIAL PRIMARY KEY
- `user_id` - INTEGER REFERENCES users(id)
- `title` - VARCHAR(255) (НЕ зашифрованное!)
- `created_at` - TIMESTAMP DEFAULT CURRENT_TIMESTAMP
- `updated_at` - TIMESTAMP DEFAULT CURRENT_TIMESTAMP
- `conversation_type` - VARCHAR(50) DEFAULT 'user_chat'
## Таблица `messages`
```sql
CREATE TABLE messages (
id SERIAL PRIMARY KEY,
conversation_id INTEGER REFERENCES conversations(id) ON DELETE CASCADE,
sender_type_encrypted TEXT NOT NULL,
sender_id INTEGER,
content_encrypted TEXT,
channel_encrypted TEXT NOT NULL,
role_encrypted TEXT NOT NULL DEFAULT 'user',
direction_encrypted TEXT,
metadata JSONB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
tokens_used INTEGER DEFAULT 0,
is_processed BOOLEAN DEFAULT false,
role VARCHAR(20) NOT NULL DEFAULT 'user',
attachment_filename TEXT,
attachment_mimetype TEXT,
attachment_size BIGINT,
attachment_data BYTEA,
direction VARCHAR(8),
message_type VARCHAR(20) DEFAULT 'public'
);
```
**Колонки:**
- `id` - SERIAL PRIMARY KEY
- `conversation_id` - INTEGER REFERENCES conversations(id)
- `sender_type_encrypted` - TEXT NOT NULL (зашифрованное)
- `sender_id` - INTEGER
- `content_encrypted` - TEXT (зашифрованное)
- `channel_encrypted` - TEXT NOT NULL (зашифрованное)
- `role_encrypted` - TEXT NOT NULL DEFAULT 'user' (зашифрованное)
- `direction_encrypted` - TEXT (зашифрованное)
- `metadata` - JSONB
- `created_at` - TIMESTAMP DEFAULT CURRENT_TIMESTAMP
- `user_id` - INTEGER REFERENCES users(id)
- `tokens_used` - INTEGER DEFAULT 0
- `is_processed` - BOOLEAN DEFAULT false
- `role` - VARCHAR(20) NOT NULL DEFAULT 'user' (НЕ зашифрованное!)
- `attachment_filename` - TEXT
- `attachment_mimetype` - TEXT
- `attachment_size` - BIGINT
- `attachment_data` - BYTEA
- `direction` - VARCHAR(8) (НЕ зашифрованное!)
- `message_type` - VARCHAR(20) DEFAULT 'public'
**Триггеры:**
- `trg_set_message_user_id` - автоматически устанавливает user_id
## Таблица `conversation_participants`
```sql
CREATE TABLE conversation_participants (
id SERIAL PRIMARY KEY,
conversation_id INTEGER REFERENCES conversations(id) ON DELETE CASCADE,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(conversation_id, user_id)
);
```
**Колонки:**
- `id` - SERIAL PRIMARY KEY
- `conversation_id` - INTEGER REFERENCES conversations(id)
- `user_id` - INTEGER REFERENCES users(id)
- `created_at` - TIMESTAMP DEFAULT CURRENT_TIMESTAMP
**Индексы:**
- PRIMARY KEY на `id`
- UNIQUE CONSTRAINT на `(conversation_id, user_id)`
- Индекс на `conversation_id`
- Индекс на `user_id`
## Таблица `admin_read_messages`
```sql
CREATE TABLE admin_read_messages (
admin_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
last_read_at TIMESTAMP NOT NULL,
PRIMARY KEY (admin_id, user_id)
);
```
**Колонки:**
- `admin_id` - INTEGER NOT NULL REFERENCES users(id) (админ)
- `user_id` - INTEGER NOT NULL REFERENCES users(id) (пользователь)
- `last_read_at` - TIMESTAMP NOT NULL (время последнего прочтения)
**Индексы:**
- PRIMARY KEY на `(admin_id, user_id)`
## Таблица `admin_read_contacts`
```sql
CREATE TABLE admin_read_contacts (
admin_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
contact_id TEXT NOT NULL,
read_at TIMESTAMP NOT NULL DEFAULT NOW(),
PRIMARY KEY (admin_id, contact_id)
);
```
**Колонки:**
- `admin_id` - INTEGER NOT NULL REFERENCES users(id) (админ)
- `contact_id` - TEXT NOT NULL (ID контакта)
- `read_at` - TIMESTAMP NOT NULL DEFAULT NOW() (время прочтения)
**Индексы:**
- PRIMARY KEY на `(admin_id, contact_id)`
- Индекс на `admin_id`
- Индекс на `contact_id`
## Таблица `user_identities`
```sql
CREATE TABLE user_identities (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
provider_encrypted TEXT NOT NULL,
provider_id_encrypted TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
**Колонки:**
- `id` - SERIAL PRIMARY KEY
- `user_id` - INTEGER REFERENCES users(id) (пользователь)
- `provider_encrypted` - TEXT NOT NULL (зашифрованный провайдер)
- `provider_id_encrypted` - TEXT NOT NULL (зашифрованный ID провайдера)
- `created_at` - TIMESTAMP DEFAULT CURRENT_TIMESTAMP
**Индексы:**
- PRIMARY KEY на `id`
- Индекс на `user_id`
## Таблица `user_preferences`
```sql
CREATE TABLE user_preferences (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
preference_key VARCHAR(50) NOT NULL,
preference_value TEXT,
metadata JSONB DEFAULT '{}',
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
UNIQUE(user_id, preference_key)
);
```
**Колонки:**
- `id` - SERIAL PRIMARY KEY
- `user_id` - INTEGER NOT NULL REFERENCES users(id) (пользователь)
- `preference_key` - VARCHAR(50) NOT NULL (ключ настройки)
- `preference_value` - TEXT (значение настройки)
- `metadata` - JSONB DEFAULT '{}' (метаданные)
- `created_at` - TIMESTAMP NOT NULL DEFAULT NOW()
- `updated_at` - TIMESTAMP NOT NULL DEFAULT NOW()
**Индексы:**
- PRIMARY KEY на `id`
- Индекс на `user_id`
- UNIQUE CONSTRAINT на `(user_id, preference_key)`
## Таблица `user_tag_links`
```sql
CREATE TABLE user_tag_links (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
tag_id INTEGER NOT NULL REFERENCES user_rows(id) ON DELETE CASCADE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, tag_id)
);
```
**Колонки:**
- `id` - SERIAL PRIMARY KEY
- `user_id` - INTEGER NOT NULL REFERENCES users(id) (пользователь)
- `tag_id` - INTEGER NOT NULL REFERENCES user_rows(id) (тег)
- `created_at` - TIMESTAMP DEFAULT CURRENT_TIMESTAMP
**Индексы:**
- PRIMARY KEY на `id`
- Индекс на `user_id`
- Индекс на `tag_id`
- UNIQUE CONSTRAINT на `(user_id, tag_id)`
## Анализ проблем в коде
Теперь, имея полную схему базы данных, давайте проверим код на соответствие:

View File

@@ -24,8 +24,6 @@ services:
- POSTGRES_DB=${DB_NAME:-dapp_db}
- POSTGRES_USER=${DB_USER:-dapp_user}
- POSTGRES_PASSWORD=${DB_PASSWORD:-dapp_password}
ports:
- '5432:5432' # Открываем доступ к базе данных извне для разработки
healthcheck:
test:
- CMD-SHELL
@@ -138,7 +136,7 @@ services:
- ./ssl:/app/ssl
- ./shared:/app/shared:ro
environment:
- NODE_ENV=${NODE_ENV:-development}
- NODE_ENV=${NODE_ENV:-production}
- PORT=${PORT:-8000}
- DB_HOST=postgres
- DB_PORT=5432
@@ -150,11 +148,12 @@ services:
- OLLAMA_BASE_URL=http://ollama:11434
- OLLAMA_MODEL=${OLLAMA_MODEL:-qwen2.5:7b}
- OLLAMA_EMBEDDINGS_MODEL=${OLLAMA_EMBEDDINGS_MODEL:-qwen2.5:7b}
- FRONTEND_URL=http://localhost:5173
# FRONTEND_URL настраивается в коде, не через env
- VECTOR_SEARCH_URL=http://vector-search:8001
# Factory адреса теперь хранятся в базе данных
ports:
- '8000:8000'
# Убираем порты для продакшна - доступ только через nginx
# ports:
# - '8000:8000'
extra_hosts:
- host.docker.internal:host-gateway
healthcheck:
@@ -164,6 +163,7 @@ services:
retries: 5
start_period: 60s
frontend:
profiles: ["dev"] # Только для разработки
build:
context: ./frontend
dockerfile: Dockerfile
@@ -204,37 +204,33 @@ services:
- "9000:80" # Frontend nginx (для production на VDS)
- "9443:443" # HTTPS порт для production на VDS
environment:
- DOMAIN=${DOMAIN:-localhost:9000}
- DOMAIN=${DOMAIN:-production.local}
- BACKEND_CONTAINER=dapp-backend
depends_on:
- backend
# SSH Key Server для безопасной передачи ключей
ssh-key-server:
image: node:20-slim
container_name: dapp-ssh-key-server
restart: unless-stopped
dns:
- 1.1.1.1 # Cloudflare (приватность)
- 9.9.9.9 # Quad9 (безопасность + блокировка вредоносных доменов)
- 8.8.8.8 # Google (надежность, fallback)
volumes:
- ./scripts/ssh-key-server.js:/app/ssh-key-server.js:ro
- ./ssl:/app/ssl
- ~/.ssh:/root/.ssh:rw
ports:
- '3001:3001'
command: node /app/ssh-key-server.js
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3001/ssh-key', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })"]
interval: 30s
timeout: 10s
retries: 3
# SSH Key Server отключен по безопасности (оставлен пример профиля dev при необходимости)
# ssh-key-server:
# profiles: ["dev"]
# image: node:20-slim
# container_name: dapp-ssh-key-server
# restart: unless-stopped
# dns:
# - 1.1.1.1
# - 9.9.9.9
# - 8.8.8.8
# volumes:
# - ./scripts/ssh-key-server.js:/app/ssh-key-server.js:ro
# - ./ssl:/app/ssl:ro
# - ~/.ssh:/root/.ssh:ro
# command: node /app/ssh-key-server.js
# # Порт намеренно не публикуется, без healthcheck
# WebSSH Agent для настройки VDS
webssh-agent:
profiles: ["dev"] # Только для разработки
build:
context: ./webssh-agent
dockerfile: Dockerfile

View File

@@ -22,8 +22,7 @@ README*
.git/
.gitignore
# Зависимости (будут установлены в контейнере)
node_modules/
# Логи установки
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@@ -9,7 +9,7 @@ echo " DOMAIN: $DOMAIN"
echo " BACKEND_CONTAINER: $BACKEND_CONTAINER"
# Выбор конфигурации в зависимости от домена
if echo "$DOMAIN" | grep -qE '^localhost(:[0-9]+)?$'; then
if echo "$DOMAIN" | grep -qE '^localhost(:[0-9]+)?$|^production\.local$'; then
echo " Режим: ЛОКАЛЬНАЯ РАЗРАБОТКА (без SSL)"
TEMPLATE_FILE="/etc/nginx/nginx-local.conf.template"
else

View File

@@ -0,0 +1,279 @@
/**
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
* All rights reserved.
*
* This software is proprietary and confidential.
* Unauthorized copying, modification, or distribution is prohibited.
*
* For licensing inquiries: info@hb3-accelerator.com
* Website: https://hb3-accelerator.com
* GitHub: https://github.com/HB3-ACCELERATOR
*/
/**
* Единая матрица прав доступа для DLE
* Используется и на backend, и на frontend
*/
// Роли в системе
const ROLES = {
GUEST: 'guest', // Неавторизованный гость
USER: 'user', // Авторизованный гость (0 токенов)
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
EDITOR: 'editor' // Админ редактор (токены >= X)
};
// Список всех прав в системе
const PERMISSIONS = {
// Публичный доступ
VIEW_HOME: 'view_home',
CHAT_AI: 'chat_ai',
// Получение сообщений
RECEIVE_MESSAGES: 'receive_messages',
// Просмотр данных
VIEW_CRM: 'view_crm',
VIEW_CONTACTS: 'view_contacts',
VIEW_DATA: 'view_data',
// Отправка сообщений
SEND_TO_USERS: 'send_to_users',
CHAT_WITH_ADMINS: 'chat_with_admins',
// AI функции
GENERATE_AI_REPLIES: 'generate_ai_replies',
// Редактирование
EDIT_USER_DATA: 'edit_user_data',
EDIT_CONTACTS: 'edit_contacts',
// Удаление
DELETE_USER_DATA: 'delete_user_data',
DELETE_MESSAGES: 'delete_messages',
// Массовые операции
BROADCAST: 'broadcast',
// Управление тегами
MANAGE_TAGS: 'manage_tags',
// Блокировка пользователей
BLOCK_USERS: 'block_users',
// Управление настройками
MANAGE_SETTINGS: 'manage_settings',
// Контент: юридические документы
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
};
// Матрица: какая роль имеет какие права
const PERMISSIONS_MAP = {
[ROLES.GUEST]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI
],
[ROLES.USER]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
],
[ROLES.READONLY]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Чтение внутренних юридических документов
PERMISSIONS.VIEW_LEGAL_DOCS
],
[ROLES.EDITOR]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
PERMISSIONS.GENERATE_AI_REPLIES,
PERMISSIONS.EDIT_USER_DATA,
PERMISSIONS.EDIT_CONTACTS,
PERMISSIONS.DELETE_USER_DATA,
PERMISSIONS.DELETE_MESSAGES,
PERMISSIONS.BROADCAST,
PERMISSIONS.MANAGE_TAGS,
PERMISSIONS.BLOCK_USERS,
PERMISSIONS.MANAGE_SETTINGS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Полный доступ к юридическим документам
PERMISSIONS.VIEW_LEGAL_DOCS,
PERMISSIONS.MANAGE_LEGAL_DOCS
]
};
/**
* Проверяет, имеет ли роль определенное право
* @param {string} role - Роль пользователя
* @param {string} permission - Требуемое право
* @returns {boolean}
*/
function hasPermission(role, permission) {
if (!role || !permission) return false;
return PERMISSIONS_MAP[role]?.includes(permission) || false;
}
/**
* Получает все права для роли
* @param {string} role - Роль пользователя
* @returns {Array<string>}
*/
function getPermissionsForRole(role) {
return PERMISSIONS_MAP[role] || [];
}
/**
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAnyPermission(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.some(p => hasPermission(role, p));
}
/**
* Проверяет, имеет ли роль ВСЕ указанные права
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAllPermissions(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.every(p => hasPermission(role, p));
}
/**
* Получает описание роли
* @param {string} role - Роль пользователя
* @returns {string}
*/
function getRoleDescription(role) {
const descriptions = {
[ROLES.GUEST]: 'Неавторизованный гость',
[ROLES.USER]: 'Авторизованный гость',
[ROLES.READONLY]: 'Админ (только чтение)',
[ROLES.EDITOR]: 'Админ (редактор)'
};
return descriptions[role] || 'Неизвестная роль';
}
/**
* Проверить, может ли отправитель отправлять сообщения получателю
* @param {string} senderRole - Роль отправителя
* @param {string} recipientRole - Роль получателя
* @param {number} senderId - ID отправителя
* @param {number} recipientId - ID получателя
* @returns {Object} { canSend: boolean, errorMessage?: string }
*/
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
// Проверяем базовое право на отправку сообщений
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
return {
canSend: false,
errorMessage: 'У вас нет права на отправку сообщений'
};
}
// Собственный чат - всегда разрешен (для ИИ ассистента)
if (senderId === recipientId) {
return { canSend: true };
}
// USER и READONLY могут писать только EDITOR
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
return { canSend: true };
}
// EDITOR может писать всем (USER, READONLY, EDITOR)
if (senderRole === 'editor') {
return { canSend: true };
}
// USER и READONLY НЕ могут писать друг другу
if ((senderRole === 'user' || senderRole === 'readonly') &&
(recipientRole === 'user' || recipientRole === 'readonly')) {
return {
canSend: false,
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
};
}
// Остальные случаи запрещены
return {
canSend: false,
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
};
}
// Экспорты для CommonJS (Node.js)
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}
// ES модули для Frontend
export {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
// CommonJS для Backend
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}

View File

@@ -129,7 +129,7 @@ import { useTagsWebSocket } from '../composables/useTagsWebSocket';
import { useContactsAndMessagesWebSocket } from '../composables/useContactsWebSocket';
import { usePermissions } from '@/composables/usePermissions';
import { useAuthContext } from '@/composables/useAuth';
import { PERMISSIONS } from '/app/shared/permissions.js';
import { PERMISSIONS } from './permissions.js';
import api from '../api/axios';
import { sendMessage, getPrivateUnreadCount } from '../services/messagesService';
import { useRoles } from '@/composables/useRoles';

View File

@@ -0,0 +1,279 @@
/**
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
* All rights reserved.
*
* This software is proprietary and confidential.
* Unauthorized copying, modification, or distribution is prohibited.
*
* For licensing inquiries: info@hb3-accelerator.com
* Website: https://hb3-accelerator.com
* GitHub: https://github.com/HB3-ACCELERATOR
*/
/**
* Единая матрица прав доступа для DLE
* Используется и на backend, и на frontend
*/
// Роли в системе
const ROLES = {
GUEST: 'guest', // Неавторизованный гость
USER: 'user', // Авторизованный гость (0 токенов)
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
EDITOR: 'editor' // Админ редактор (токены >= X)
};
// Список всех прав в системе
const PERMISSIONS = {
// Публичный доступ
VIEW_HOME: 'view_home',
CHAT_AI: 'chat_ai',
// Получение сообщений
RECEIVE_MESSAGES: 'receive_messages',
// Просмотр данных
VIEW_CRM: 'view_crm',
VIEW_CONTACTS: 'view_contacts',
VIEW_DATA: 'view_data',
// Отправка сообщений
SEND_TO_USERS: 'send_to_users',
CHAT_WITH_ADMINS: 'chat_with_admins',
// AI функции
GENERATE_AI_REPLIES: 'generate_ai_replies',
// Редактирование
EDIT_USER_DATA: 'edit_user_data',
EDIT_CONTACTS: 'edit_contacts',
// Удаление
DELETE_USER_DATA: 'delete_user_data',
DELETE_MESSAGES: 'delete_messages',
// Массовые операции
BROADCAST: 'broadcast',
// Управление тегами
MANAGE_TAGS: 'manage_tags',
// Блокировка пользователей
BLOCK_USERS: 'block_users',
// Управление настройками
MANAGE_SETTINGS: 'manage_settings',
// Контент: юридические документы
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
};
// Матрица: какая роль имеет какие права
const PERMISSIONS_MAP = {
[ROLES.GUEST]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI
],
[ROLES.USER]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
],
[ROLES.READONLY]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Чтение внутренних юридических документов
PERMISSIONS.VIEW_LEGAL_DOCS
],
[ROLES.EDITOR]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
PERMISSIONS.GENERATE_AI_REPLIES,
PERMISSIONS.EDIT_USER_DATA,
PERMISSIONS.EDIT_CONTACTS,
PERMISSIONS.DELETE_USER_DATA,
PERMISSIONS.DELETE_MESSAGES,
PERMISSIONS.BROADCAST,
PERMISSIONS.MANAGE_TAGS,
PERMISSIONS.BLOCK_USERS,
PERMISSIONS.MANAGE_SETTINGS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Полный доступ к юридическим документам
PERMISSIONS.VIEW_LEGAL_DOCS,
PERMISSIONS.MANAGE_LEGAL_DOCS
]
};
/**
* Проверяет, имеет ли роль определенное право
* @param {string} role - Роль пользователя
* @param {string} permission - Требуемое право
* @returns {boolean}
*/
function hasPermission(role, permission) {
if (!role || !permission) return false;
return PERMISSIONS_MAP[role]?.includes(permission) || false;
}
/**
* Получает все права для роли
* @param {string} role - Роль пользователя
* @returns {Array<string>}
*/
function getPermissionsForRole(role) {
return PERMISSIONS_MAP[role] || [];
}
/**
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAnyPermission(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.some(p => hasPermission(role, p));
}
/**
* Проверяет, имеет ли роль ВСЕ указанные права
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAllPermissions(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.every(p => hasPermission(role, p));
}
/**
* Получает описание роли
* @param {string} role - Роль пользователя
* @returns {string}
*/
function getRoleDescription(role) {
const descriptions = {
[ROLES.GUEST]: 'Неавторизованный гость',
[ROLES.USER]: 'Авторизованный гость',
[ROLES.READONLY]: 'Админ (только чтение)',
[ROLES.EDITOR]: 'Админ (редактор)'
};
return descriptions[role] || 'Неизвестная роль';
}
/**
* Проверить, может ли отправитель отправлять сообщения получателю
* @param {string} senderRole - Роль отправителя
* @param {string} recipientRole - Роль получателя
* @param {number} senderId - ID отправителя
* @param {number} recipientId - ID получателя
* @returns {Object} { canSend: boolean, errorMessage?: string }
*/
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
// Проверяем базовое право на отправку сообщений
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
return {
canSend: false,
errorMessage: 'У вас нет права на отправку сообщений'
};
}
// Собственный чат - всегда разрешен (для ИИ ассистента)
if (senderId === recipientId) {
return { canSend: true };
}
// USER и READONLY могут писать только EDITOR
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
return { canSend: true };
}
// EDITOR может писать всем (USER, READONLY, EDITOR)
if (senderRole === 'editor') {
return { canSend: true };
}
// USER и READONLY НЕ могут писать друг другу
if ((senderRole === 'user' || senderRole === 'readonly') &&
(recipientRole === 'user' || recipientRole === 'readonly')) {
return {
canSend: false,
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
};
}
// Остальные случаи запрещены
return {
canSend: false,
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
};
}
// Экспорты для CommonJS (Node.js)
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}
// ES модули для Frontend
export {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
// CommonJS для Backend
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}

View File

@@ -0,0 +1,279 @@
/**
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
* All rights reserved.
*
* This software is proprietary and confidential.
* Unauthorized copying, modification, or distribution is prohibited.
*
* For licensing inquiries: info@hb3-accelerator.com
* Website: https://hb3-accelerator.com
* GitHub: https://github.com/HB3-ACCELERATOR
*/
/**
* Единая матрица прав доступа для DLE
* Используется и на backend, и на frontend
*/
// Роли в системе
const ROLES = {
GUEST: 'guest', // Неавторизованный гость
USER: 'user', // Авторизованный гость (0 токенов)
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
EDITOR: 'editor' // Админ редактор (токены >= X)
};
// Список всех прав в системе
const PERMISSIONS = {
// Публичный доступ
VIEW_HOME: 'view_home',
CHAT_AI: 'chat_ai',
// Получение сообщений
RECEIVE_MESSAGES: 'receive_messages',
// Просмотр данных
VIEW_CRM: 'view_crm',
VIEW_CONTACTS: 'view_contacts',
VIEW_DATA: 'view_data',
// Отправка сообщений
SEND_TO_USERS: 'send_to_users',
CHAT_WITH_ADMINS: 'chat_with_admins',
// AI функции
GENERATE_AI_REPLIES: 'generate_ai_replies',
// Редактирование
EDIT_USER_DATA: 'edit_user_data',
EDIT_CONTACTS: 'edit_contacts',
// Удаление
DELETE_USER_DATA: 'delete_user_data',
DELETE_MESSAGES: 'delete_messages',
// Массовые операции
BROADCAST: 'broadcast',
// Управление тегами
MANAGE_TAGS: 'manage_tags',
// Блокировка пользователей
BLOCK_USERS: 'block_users',
// Управление настройками
MANAGE_SETTINGS: 'manage_settings',
// Контент: юридические документы
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
};
// Матрица: какая роль имеет какие права
const PERMISSIONS_MAP = {
[ROLES.GUEST]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI
],
[ROLES.USER]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
],
[ROLES.READONLY]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Чтение внутренних юридических документов
PERMISSIONS.VIEW_LEGAL_DOCS
],
[ROLES.EDITOR]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
PERMISSIONS.GENERATE_AI_REPLIES,
PERMISSIONS.EDIT_USER_DATA,
PERMISSIONS.EDIT_CONTACTS,
PERMISSIONS.DELETE_USER_DATA,
PERMISSIONS.DELETE_MESSAGES,
PERMISSIONS.BROADCAST,
PERMISSIONS.MANAGE_TAGS,
PERMISSIONS.BLOCK_USERS,
PERMISSIONS.MANAGE_SETTINGS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Полный доступ к юридическим документам
PERMISSIONS.VIEW_LEGAL_DOCS,
PERMISSIONS.MANAGE_LEGAL_DOCS
]
};
/**
* Проверяет, имеет ли роль определенное право
* @param {string} role - Роль пользователя
* @param {string} permission - Требуемое право
* @returns {boolean}
*/
function hasPermission(role, permission) {
if (!role || !permission) return false;
return PERMISSIONS_MAP[role]?.includes(permission) || false;
}
/**
* Получает все права для роли
* @param {string} role - Роль пользователя
* @returns {Array<string>}
*/
function getPermissionsForRole(role) {
return PERMISSIONS_MAP[role] || [];
}
/**
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAnyPermission(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.some(p => hasPermission(role, p));
}
/**
* Проверяет, имеет ли роль ВСЕ указанные права
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAllPermissions(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.every(p => hasPermission(role, p));
}
/**
* Получает описание роли
* @param {string} role - Роль пользователя
* @returns {string}
*/
function getRoleDescription(role) {
const descriptions = {
[ROLES.GUEST]: 'Неавторизованный гость',
[ROLES.USER]: 'Авторизованный гость',
[ROLES.READONLY]: 'Админ (только чтение)',
[ROLES.EDITOR]: 'Админ (редактор)'
};
return descriptions[role] || 'Неизвестная роль';
}
/**
* Проверить, может ли отправитель отправлять сообщения получателю
* @param {string} senderRole - Роль отправителя
* @param {string} recipientRole - Роль получателя
* @param {number} senderId - ID отправителя
* @param {number} recipientId - ID получателя
* @returns {Object} { canSend: boolean, errorMessage?: string }
*/
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
// Проверяем базовое право на отправку сообщений
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
return {
canSend: false,
errorMessage: 'У вас нет права на отправку сообщений'
};
}
// Собственный чат - всегда разрешен (для ИИ ассистента)
if (senderId === recipientId) {
return { canSend: true };
}
// USER и READONLY могут писать только EDITOR
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
return { canSend: true };
}
// EDITOR может писать всем (USER, READONLY, EDITOR)
if (senderRole === 'editor') {
return { canSend: true };
}
// USER и READONLY НЕ могут писать друг другу
if ((senderRole === 'user' || senderRole === 'readonly') &&
(recipientRole === 'user' || recipientRole === 'readonly')) {
return {
canSend: false,
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
};
}
// Остальные случаи запрещены
return {
canSend: false,
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
};
}
// Экспорты для CommonJS (Node.js)
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}
// ES модули для Frontend
export {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
// CommonJS для Backend
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}

View File

@@ -12,7 +12,7 @@
import { computed } from 'vue';
import { useAuthContext } from './useAuth';
import { PERMISSIONS, ROLES, hasPermission as checkPermission, getRoleDescription } from '/app/shared/permissions';
import { PERMISSIONS, ROLES, hasPermission as checkPermission, getRoleDescription } from './permissions.js';
/**
* Composable для работы с правами доступа

View File

@@ -19,7 +19,7 @@ const SettingsInterfaceView = () => import('../views/settings/Interface/Interfac
import axios from 'axios';
import { setToStorage } from '../utils/storage.js';
import { PERMISSIONS, hasPermission } from '/app/shared/permissions.js';
import { PERMISSIONS, hasPermission } from './permissions.js';
// console.log('router/index.js: Script loaded');

View File

@@ -0,0 +1,279 @@
/**
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
* All rights reserved.
*
* This software is proprietary and confidential.
* Unauthorized copying, modification, or distribution is prohibited.
*
* For licensing inquiries: info@hb3-accelerator.com
* Website: https://hb3-accelerator.com
* GitHub: https://github.com/HB3-ACCELERATOR
*/
/**
* Единая матрица прав доступа для DLE
* Используется и на backend, и на frontend
*/
// Роли в системе
const ROLES = {
GUEST: 'guest', // Неавторизованный гость
USER: 'user', // Авторизованный гость (0 токенов)
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
EDITOR: 'editor' // Админ редактор (токены >= X)
};
// Список всех прав в системе
const PERMISSIONS = {
// Публичный доступ
VIEW_HOME: 'view_home',
CHAT_AI: 'chat_ai',
// Получение сообщений
RECEIVE_MESSAGES: 'receive_messages',
// Просмотр данных
VIEW_CRM: 'view_crm',
VIEW_CONTACTS: 'view_contacts',
VIEW_DATA: 'view_data',
// Отправка сообщений
SEND_TO_USERS: 'send_to_users',
CHAT_WITH_ADMINS: 'chat_with_admins',
// AI функции
GENERATE_AI_REPLIES: 'generate_ai_replies',
// Редактирование
EDIT_USER_DATA: 'edit_user_data',
EDIT_CONTACTS: 'edit_contacts',
// Удаление
DELETE_USER_DATA: 'delete_user_data',
DELETE_MESSAGES: 'delete_messages',
// Массовые операции
BROADCAST: 'broadcast',
// Управление тегами
MANAGE_TAGS: 'manage_tags',
// Блокировка пользователей
BLOCK_USERS: 'block_users',
// Управление настройками
MANAGE_SETTINGS: 'manage_settings',
// Контент: юридические документы
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
};
// Матрица: какая роль имеет какие права
const PERMISSIONS_MAP = {
[ROLES.GUEST]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI
],
[ROLES.USER]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
],
[ROLES.READONLY]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Чтение внутренних юридических документов
PERMISSIONS.VIEW_LEGAL_DOCS
],
[ROLES.EDITOR]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
PERMISSIONS.GENERATE_AI_REPLIES,
PERMISSIONS.EDIT_USER_DATA,
PERMISSIONS.EDIT_CONTACTS,
PERMISSIONS.DELETE_USER_DATA,
PERMISSIONS.DELETE_MESSAGES,
PERMISSIONS.BROADCAST,
PERMISSIONS.MANAGE_TAGS,
PERMISSIONS.BLOCK_USERS,
PERMISSIONS.MANAGE_SETTINGS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Полный доступ к юридическим документам
PERMISSIONS.VIEW_LEGAL_DOCS,
PERMISSIONS.MANAGE_LEGAL_DOCS
]
};
/**
* Проверяет, имеет ли роль определенное право
* @param {string} role - Роль пользователя
* @param {string} permission - Требуемое право
* @returns {boolean}
*/
function hasPermission(role, permission) {
if (!role || !permission) return false;
return PERMISSIONS_MAP[role]?.includes(permission) || false;
}
/**
* Получает все права для роли
* @param {string} role - Роль пользователя
* @returns {Array<string>}
*/
function getPermissionsForRole(role) {
return PERMISSIONS_MAP[role] || [];
}
/**
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAnyPermission(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.some(p => hasPermission(role, p));
}
/**
* Проверяет, имеет ли роль ВСЕ указанные права
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAllPermissions(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.every(p => hasPermission(role, p));
}
/**
* Получает описание роли
* @param {string} role - Роль пользователя
* @returns {string}
*/
function getRoleDescription(role) {
const descriptions = {
[ROLES.GUEST]: 'Неавторизованный гость',
[ROLES.USER]: 'Авторизованный гость',
[ROLES.READONLY]: 'Админ (только чтение)',
[ROLES.EDITOR]: 'Админ (редактор)'
};
return descriptions[role] || 'Неизвестная роль';
}
/**
* Проверить, может ли отправитель отправлять сообщения получателю
* @param {string} senderRole - Роль отправителя
* @param {string} recipientRole - Роль получателя
* @param {number} senderId - ID отправителя
* @param {number} recipientId - ID получателя
* @returns {Object} { canSend: boolean, errorMessage?: string }
*/
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
// Проверяем базовое право на отправку сообщений
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
return {
canSend: false,
errorMessage: 'У вас нет права на отправку сообщений'
};
}
// Собственный чат - всегда разрешен (для ИИ ассистента)
if (senderId === recipientId) {
return { canSend: true };
}
// USER и READONLY могут писать только EDITOR
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
return { canSend: true };
}
// EDITOR может писать всем (USER, READONLY, EDITOR)
if (senderRole === 'editor') {
return { canSend: true };
}
// USER и READONLY НЕ могут писать друг другу
if ((senderRole === 'user' || senderRole === 'readonly') &&
(recipientRole === 'user' || recipientRole === 'readonly')) {
return {
canSend: false,
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
};
}
// Остальные случаи запрещены
return {
canSend: false,
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
};
}
// Экспорты для CommonJS (Node.js)
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}
// ES модули для Frontend
export {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
// CommonJS для Backend
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}

View File

@@ -0,0 +1,279 @@
/**
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
* All rights reserved.
*
* This software is proprietary and confidential.
* Unauthorized copying, modification, or distribution is prohibited.
*
* For licensing inquiries: info@hb3-accelerator.com
* Website: https://hb3-accelerator.com
* GitHub: https://github.com/HB3-ACCELERATOR
*/
/**
* Единая матрица прав доступа для DLE
* Используется и на backend, и на frontend
*/
// Роли в системе
const ROLES = {
GUEST: 'guest', // Неавторизованный гость
USER: 'user', // Авторизованный гость (0 токенов)
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
EDITOR: 'editor' // Админ редактор (токены >= X)
};
// Список всех прав в системе
const PERMISSIONS = {
// Публичный доступ
VIEW_HOME: 'view_home',
CHAT_AI: 'chat_ai',
// Получение сообщений
RECEIVE_MESSAGES: 'receive_messages',
// Просмотр данных
VIEW_CRM: 'view_crm',
VIEW_CONTACTS: 'view_contacts',
VIEW_DATA: 'view_data',
// Отправка сообщений
SEND_TO_USERS: 'send_to_users',
CHAT_WITH_ADMINS: 'chat_with_admins',
// AI функции
GENERATE_AI_REPLIES: 'generate_ai_replies',
// Редактирование
EDIT_USER_DATA: 'edit_user_data',
EDIT_CONTACTS: 'edit_contacts',
// Удаление
DELETE_USER_DATA: 'delete_user_data',
DELETE_MESSAGES: 'delete_messages',
// Массовые операции
BROADCAST: 'broadcast',
// Управление тегами
MANAGE_TAGS: 'manage_tags',
// Блокировка пользователей
BLOCK_USERS: 'block_users',
// Управление настройками
MANAGE_SETTINGS: 'manage_settings',
// Контент: юридические документы
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
};
// Матрица: какая роль имеет какие права
const PERMISSIONS_MAP = {
[ROLES.GUEST]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI
],
[ROLES.USER]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
],
[ROLES.READONLY]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Чтение внутренних юридических документов
PERMISSIONS.VIEW_LEGAL_DOCS
],
[ROLES.EDITOR]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
PERMISSIONS.GENERATE_AI_REPLIES,
PERMISSIONS.EDIT_USER_DATA,
PERMISSIONS.EDIT_CONTACTS,
PERMISSIONS.DELETE_USER_DATA,
PERMISSIONS.DELETE_MESSAGES,
PERMISSIONS.BROADCAST,
PERMISSIONS.MANAGE_TAGS,
PERMISSIONS.BLOCK_USERS,
PERMISSIONS.MANAGE_SETTINGS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Полный доступ к юридическим документам
PERMISSIONS.VIEW_LEGAL_DOCS,
PERMISSIONS.MANAGE_LEGAL_DOCS
]
};
/**
* Проверяет, имеет ли роль определенное право
* @param {string} role - Роль пользователя
* @param {string} permission - Требуемое право
* @returns {boolean}
*/
function hasPermission(role, permission) {
if (!role || !permission) return false;
return PERMISSIONS_MAP[role]?.includes(permission) || false;
}
/**
* Получает все права для роли
* @param {string} role - Роль пользователя
* @returns {Array<string>}
*/
function getPermissionsForRole(role) {
return PERMISSIONS_MAP[role] || [];
}
/**
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAnyPermission(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.some(p => hasPermission(role, p));
}
/**
* Проверяет, имеет ли роль ВСЕ указанные права
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAllPermissions(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.every(p => hasPermission(role, p));
}
/**
* Получает описание роли
* @param {string} role - Роль пользователя
* @returns {string}
*/
function getRoleDescription(role) {
const descriptions = {
[ROLES.GUEST]: 'Неавторизованный гость',
[ROLES.USER]: 'Авторизованный гость',
[ROLES.READONLY]: 'Админ (только чтение)',
[ROLES.EDITOR]: 'Админ (редактор)'
};
return descriptions[role] || 'Неизвестная роль';
}
/**
* Проверить, может ли отправитель отправлять сообщения получателю
* @param {string} senderRole - Роль отправителя
* @param {string} recipientRole - Роль получателя
* @param {number} senderId - ID отправителя
* @param {number} recipientId - ID получателя
* @returns {Object} { canSend: boolean, errorMessage?: string }
*/
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
// Проверяем базовое право на отправку сообщений
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
return {
canSend: false,
errorMessage: 'У вас нет права на отправку сообщений'
};
}
// Собственный чат - всегда разрешен (для ИИ ассистента)
if (senderId === recipientId) {
return { canSend: true };
}
// USER и READONLY могут писать только EDITOR
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
return { canSend: true };
}
// EDITOR может писать всем (USER, READONLY, EDITOR)
if (senderRole === 'editor') {
return { canSend: true };
}
// USER и READONLY НЕ могут писать друг другу
if ((senderRole === 'user' || senderRole === 'readonly') &&
(recipientRole === 'user' || recipientRole === 'readonly')) {
return {
canSend: false,
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
};
}
// Остальные случаи запрещены
return {
canSend: false,
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
};
}
// Экспорты для CommonJS (Node.js)
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}
// ES модули для Frontend
export {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
// CommonJS для Backend
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}

View File

@@ -178,7 +178,7 @@ import { ref, computed, onMounted } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import BaseLayout from '../components/BaseLayout.vue';
import pagesService from '../services/pagesService';
import { PERMISSIONS } from '/app/shared/permissions.js';
import { PERMISSIONS } from './permissions.js';
import { useAuthContext } from '../composables/useAuth';
import { usePermissions } from '../composables/usePermissions';

View File

@@ -167,7 +167,7 @@ import messagesService from '../../services/messagesService.js';
import { getPublicMessages, getConversationByUserId, sendMessage, getPersonalChatHistory } from '../../services/messagesService.js';
import { useAuthContext } from '@/composables/useAuth';
import { usePermissions } from '@/composables/usePermissions';
import { PERMISSIONS } from '/app/shared/permissions.js';
import { PERMISSIONS } from './permissions.js';
import { useContactsAndMessagesWebSocket } from '@/composables/useContactsWebSocket';
const { canEditContacts, canDeleteData, canManageTags, canBlockUsers, canSendToUsers, canGenerateAI, canViewContacts, hasPermission } = usePermissions();
const { address, userId: currentUserId } = useAuthContext();

View File

@@ -0,0 +1,279 @@
/**
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
* All rights reserved.
*
* This software is proprietary and confidential.
* Unauthorized copying, modification, or distribution is prohibited.
*
* For licensing inquiries: info@hb3-accelerator.com
* Website: https://hb3-accelerator.com
* GitHub: https://github.com/HB3-ACCELERATOR
*/
/**
* Единая матрица прав доступа для DLE
* Используется и на backend, и на frontend
*/
// Роли в системе
const ROLES = {
GUEST: 'guest', // Неавторизованный гость
USER: 'user', // Авторизованный гость (0 токенов)
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
EDITOR: 'editor' // Админ редактор (токены >= X)
};
// Список всех прав в системе
const PERMISSIONS = {
// Публичный доступ
VIEW_HOME: 'view_home',
CHAT_AI: 'chat_ai',
// Получение сообщений
RECEIVE_MESSAGES: 'receive_messages',
// Просмотр данных
VIEW_CRM: 'view_crm',
VIEW_CONTACTS: 'view_contacts',
VIEW_DATA: 'view_data',
// Отправка сообщений
SEND_TO_USERS: 'send_to_users',
CHAT_WITH_ADMINS: 'chat_with_admins',
// AI функции
GENERATE_AI_REPLIES: 'generate_ai_replies',
// Редактирование
EDIT_USER_DATA: 'edit_user_data',
EDIT_CONTACTS: 'edit_contacts',
// Удаление
DELETE_USER_DATA: 'delete_user_data',
DELETE_MESSAGES: 'delete_messages',
// Массовые операции
BROADCAST: 'broadcast',
// Управление тегами
MANAGE_TAGS: 'manage_tags',
// Блокировка пользователей
BLOCK_USERS: 'block_users',
// Управление настройками
MANAGE_SETTINGS: 'manage_settings',
// Контент: юридические документы
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
};
// Матрица: какая роль имеет какие права
const PERMISSIONS_MAP = {
[ROLES.GUEST]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI
],
[ROLES.USER]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
],
[ROLES.READONLY]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Чтение внутренних юридических документов
PERMISSIONS.VIEW_LEGAL_DOCS
],
[ROLES.EDITOR]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
PERMISSIONS.GENERATE_AI_REPLIES,
PERMISSIONS.EDIT_USER_DATA,
PERMISSIONS.EDIT_CONTACTS,
PERMISSIONS.DELETE_USER_DATA,
PERMISSIONS.DELETE_MESSAGES,
PERMISSIONS.BROADCAST,
PERMISSIONS.MANAGE_TAGS,
PERMISSIONS.BLOCK_USERS,
PERMISSIONS.MANAGE_SETTINGS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Полный доступ к юридическим документам
PERMISSIONS.VIEW_LEGAL_DOCS,
PERMISSIONS.MANAGE_LEGAL_DOCS
]
};
/**
* Проверяет, имеет ли роль определенное право
* @param {string} role - Роль пользователя
* @param {string} permission - Требуемое право
* @returns {boolean}
*/
function hasPermission(role, permission) {
if (!role || !permission) return false;
return PERMISSIONS_MAP[role]?.includes(permission) || false;
}
/**
* Получает все права для роли
* @param {string} role - Роль пользователя
* @returns {Array<string>}
*/
function getPermissionsForRole(role) {
return PERMISSIONS_MAP[role] || [];
}
/**
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAnyPermission(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.some(p => hasPermission(role, p));
}
/**
* Проверяет, имеет ли роль ВСЕ указанные права
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAllPermissions(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.every(p => hasPermission(role, p));
}
/**
* Получает описание роли
* @param {string} role - Роль пользователя
* @returns {string}
*/
function getRoleDescription(role) {
const descriptions = {
[ROLES.GUEST]: 'Неавторизованный гость',
[ROLES.USER]: 'Авторизованный гость',
[ROLES.READONLY]: 'Админ (только чтение)',
[ROLES.EDITOR]: 'Админ (редактор)'
};
return descriptions[role] || 'Неизвестная роль';
}
/**
* Проверить, может ли отправитель отправлять сообщения получателю
* @param {string} senderRole - Роль отправителя
* @param {string} recipientRole - Роль получателя
* @param {number} senderId - ID отправителя
* @param {number} recipientId - ID получателя
* @returns {Object} { canSend: boolean, errorMessage?: string }
*/
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
// Проверяем базовое право на отправку сообщений
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
return {
canSend: false,
errorMessage: 'У вас нет права на отправку сообщений'
};
}
// Собственный чат - всегда разрешен (для ИИ ассистента)
if (senderId === recipientId) {
return { canSend: true };
}
// USER и READONLY могут писать только EDITOR
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
return { canSend: true };
}
// EDITOR может писать всем (USER, READONLY, EDITOR)
if (senderRole === 'editor') {
return { canSend: true };
}
// USER и READONLY НЕ могут писать друг другу
if ((senderRole === 'user' || senderRole === 'readonly') &&
(recipientRole === 'user' || recipientRole === 'readonly')) {
return {
canSend: false,
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
};
}
// Остальные случаи запрещены
return {
canSend: false,
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
};
}
// Экспорты для CommonJS (Node.js)
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}
// ES модули для Frontend
export {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
// CommonJS для Backend
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}

View File

@@ -60,7 +60,7 @@ import BaseLayout from '../../components/BaseLayout.vue';
import pagesService from '../../services/pagesService';
import { useAuthContext } from '../../composables/useAuth';
import { usePermissions } from '../../composables/usePermissions';
import { PERMISSIONS } from '/app/shared/permissions.js';
import { PERMISSIONS } from './permissions.js';
const props = defineProps({
isAuthenticated: { type: Boolean, default: false },

View File

@@ -55,7 +55,7 @@ import pagesService from '../../services/pagesService';
import api from '../../api/axios';
import { useAuthContext } from '../../composables/useAuth';
import { usePermissions } from '../../composables/usePermissions';
import { PERMISSIONS as SHARED_PERMISSIONS } from '/app/shared/permissions.js';
import { PERMISSIONS as SHARED_PERMISSIONS } from './permissions.js';
const props = defineProps({
isAuthenticated: { type: Boolean, default: false },

View File

@@ -0,0 +1,279 @@
/**
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
* All rights reserved.
*
* This software is proprietary and confidential.
* Unauthorized copying, modification, or distribution is prohibited.
*
* For licensing inquiries: info@hb3-accelerator.com
* Website: https://hb3-accelerator.com
* GitHub: https://github.com/HB3-ACCELERATOR
*/
/**
* Единая матрица прав доступа для DLE
* Используется и на backend, и на frontend
*/
// Роли в системе
const ROLES = {
GUEST: 'guest', // Неавторизованный гость
USER: 'user', // Авторизованный гость (0 токенов)
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
EDITOR: 'editor' // Админ редактор (токены >= X)
};
// Список всех прав в системе
const PERMISSIONS = {
// Публичный доступ
VIEW_HOME: 'view_home',
CHAT_AI: 'chat_ai',
// Получение сообщений
RECEIVE_MESSAGES: 'receive_messages',
// Просмотр данных
VIEW_CRM: 'view_crm',
VIEW_CONTACTS: 'view_contacts',
VIEW_DATA: 'view_data',
// Отправка сообщений
SEND_TO_USERS: 'send_to_users',
CHAT_WITH_ADMINS: 'chat_with_admins',
// AI функции
GENERATE_AI_REPLIES: 'generate_ai_replies',
// Редактирование
EDIT_USER_DATA: 'edit_user_data',
EDIT_CONTACTS: 'edit_contacts',
// Удаление
DELETE_USER_DATA: 'delete_user_data',
DELETE_MESSAGES: 'delete_messages',
// Массовые операции
BROADCAST: 'broadcast',
// Управление тегами
MANAGE_TAGS: 'manage_tags',
// Блокировка пользователей
BLOCK_USERS: 'block_users',
// Управление настройками
MANAGE_SETTINGS: 'manage_settings',
// Контент: юридические документы
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
};
// Матрица: какая роль имеет какие права
const PERMISSIONS_MAP = {
[ROLES.GUEST]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI
],
[ROLES.USER]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
],
[ROLES.READONLY]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Чтение внутренних юридических документов
PERMISSIONS.VIEW_LEGAL_DOCS
],
[ROLES.EDITOR]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
PERMISSIONS.GENERATE_AI_REPLIES,
PERMISSIONS.EDIT_USER_DATA,
PERMISSIONS.EDIT_CONTACTS,
PERMISSIONS.DELETE_USER_DATA,
PERMISSIONS.DELETE_MESSAGES,
PERMISSIONS.BROADCAST,
PERMISSIONS.MANAGE_TAGS,
PERMISSIONS.BLOCK_USERS,
PERMISSIONS.MANAGE_SETTINGS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Полный доступ к юридическим документам
PERMISSIONS.VIEW_LEGAL_DOCS,
PERMISSIONS.MANAGE_LEGAL_DOCS
]
};
/**
* Проверяет, имеет ли роль определенное право
* @param {string} role - Роль пользователя
* @param {string} permission - Требуемое право
* @returns {boolean}
*/
function hasPermission(role, permission) {
if (!role || !permission) return false;
return PERMISSIONS_MAP[role]?.includes(permission) || false;
}
/**
* Получает все права для роли
* @param {string} role - Роль пользователя
* @returns {Array<string>}
*/
function getPermissionsForRole(role) {
return PERMISSIONS_MAP[role] || [];
}
/**
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAnyPermission(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.some(p => hasPermission(role, p));
}
/**
* Проверяет, имеет ли роль ВСЕ указанные права
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAllPermissions(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.every(p => hasPermission(role, p));
}
/**
* Получает описание роли
* @param {string} role - Роль пользователя
* @returns {string}
*/
function getRoleDescription(role) {
const descriptions = {
[ROLES.GUEST]: 'Неавторизованный гость',
[ROLES.USER]: 'Авторизованный гость',
[ROLES.READONLY]: 'Админ (только чтение)',
[ROLES.EDITOR]: 'Админ (редактор)'
};
return descriptions[role] || 'Неизвестная роль';
}
/**
* Проверить, может ли отправитель отправлять сообщения получателю
* @param {string} senderRole - Роль отправителя
* @param {string} recipientRole - Роль получателя
* @param {number} senderId - ID отправителя
* @param {number} recipientId - ID получателя
* @returns {Object} { canSend: boolean, errorMessage?: string }
*/
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
// Проверяем базовое право на отправку сообщений
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
return {
canSend: false,
errorMessage: 'У вас нет права на отправку сообщений'
};
}
// Собственный чат - всегда разрешен (для ИИ ассистента)
if (senderId === recipientId) {
return { canSend: true };
}
// USER и READONLY могут писать только EDITOR
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
return { canSend: true };
}
// EDITOR может писать всем (USER, READONLY, EDITOR)
if (senderRole === 'editor') {
return { canSend: true };
}
// USER и READONLY НЕ могут писать друг другу
if ((senderRole === 'user' || senderRole === 'readonly') &&
(recipientRole === 'user' || recipientRole === 'readonly')) {
return {
canSend: false,
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
};
}
// Остальные случаи запрещены
return {
canSend: false,
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
};
}
// Экспорты для CommonJS (Node.js)
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}
// ES модули для Frontend
export {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
// CommonJS для Backend
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}

View File

@@ -0,0 +1,279 @@
/**
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
* All rights reserved.
*
* This software is proprietary and confidential.
* Unauthorized copying, modification, or distribution is prohibited.
*
* For licensing inquiries: info@hb3-accelerator.com
* Website: https://hb3-accelerator.com
* GitHub: https://github.com/HB3-ACCELERATOR
*/
/**
* Единая матрица прав доступа для DLE
* Используется и на backend, и на frontend
*/
// Роли в системе
const ROLES = {
GUEST: 'guest', // Неавторизованный гость
USER: 'user', // Авторизованный гость (0 токенов)
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
EDITOR: 'editor' // Админ редактор (токены >= X)
};
// Список всех прав в системе
const PERMISSIONS = {
// Публичный доступ
VIEW_HOME: 'view_home',
CHAT_AI: 'chat_ai',
// Получение сообщений
RECEIVE_MESSAGES: 'receive_messages',
// Просмотр данных
VIEW_CRM: 'view_crm',
VIEW_CONTACTS: 'view_contacts',
VIEW_DATA: 'view_data',
// Отправка сообщений
SEND_TO_USERS: 'send_to_users',
CHAT_WITH_ADMINS: 'chat_with_admins',
// AI функции
GENERATE_AI_REPLIES: 'generate_ai_replies',
// Редактирование
EDIT_USER_DATA: 'edit_user_data',
EDIT_CONTACTS: 'edit_contacts',
// Удаление
DELETE_USER_DATA: 'delete_user_data',
DELETE_MESSAGES: 'delete_messages',
// Массовые операции
BROADCAST: 'broadcast',
// Управление тегами
MANAGE_TAGS: 'manage_tags',
// Блокировка пользователей
BLOCK_USERS: 'block_users',
// Управление настройками
MANAGE_SETTINGS: 'manage_settings',
// Контент: юридические документы
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
};
// Матрица: какая роль имеет какие права
const PERMISSIONS_MAP = {
[ROLES.GUEST]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI
],
[ROLES.USER]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
],
[ROLES.READONLY]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Чтение внутренних юридических документов
PERMISSIONS.VIEW_LEGAL_DOCS
],
[ROLES.EDITOR]: [
PERMISSIONS.VIEW_HOME,
PERMISSIONS.CHAT_AI,
PERMISSIONS.RECEIVE_MESSAGES,
PERMISSIONS.VIEW_CRM,
PERMISSIONS.VIEW_CONTACTS,
PERMISSIONS.VIEW_DATA,
PERMISSIONS.SEND_TO_USERS,
PERMISSIONS.CHAT_WITH_ADMINS,
PERMISSIONS.GENERATE_AI_REPLIES,
PERMISSIONS.EDIT_USER_DATA,
PERMISSIONS.EDIT_CONTACTS,
PERMISSIONS.DELETE_USER_DATA,
PERMISSIONS.DELETE_MESSAGES,
PERMISSIONS.BROADCAST,
PERMISSIONS.MANAGE_TAGS,
PERMISSIONS.BLOCK_USERS,
PERMISSIONS.MANAGE_SETTINGS,
// Базовые документы для пользователей
PERMISSIONS.VIEW_BASIC_DOCS,
// Полный доступ к юридическим документам
PERMISSIONS.VIEW_LEGAL_DOCS,
PERMISSIONS.MANAGE_LEGAL_DOCS
]
};
/**
* Проверяет, имеет ли роль определенное право
* @param {string} role - Роль пользователя
* @param {string} permission - Требуемое право
* @returns {boolean}
*/
function hasPermission(role, permission) {
if (!role || !permission) return false;
return PERMISSIONS_MAP[role]?.includes(permission) || false;
}
/**
* Получает все права для роли
* @param {string} role - Роль пользователя
* @returns {Array<string>}
*/
function getPermissionsForRole(role) {
return PERMISSIONS_MAP[role] || [];
}
/**
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAnyPermission(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.some(p => hasPermission(role, p));
}
/**
* Проверяет, имеет ли роль ВСЕ указанные права
* @param {string} role - Роль пользователя
* @param {Array<string>} permissions - Список прав
* @returns {boolean}
*/
function hasAllPermissions(role, permissions) {
if (!Array.isArray(permissions)) return false;
return permissions.every(p => hasPermission(role, p));
}
/**
* Получает описание роли
* @param {string} role - Роль пользователя
* @returns {string}
*/
function getRoleDescription(role) {
const descriptions = {
[ROLES.GUEST]: 'Неавторизованный гость',
[ROLES.USER]: 'Авторизованный гость',
[ROLES.READONLY]: 'Админ (только чтение)',
[ROLES.EDITOR]: 'Админ (редактор)'
};
return descriptions[role] || 'Неизвестная роль';
}
/**
* Проверить, может ли отправитель отправлять сообщения получателю
* @param {string} senderRole - Роль отправителя
* @param {string} recipientRole - Роль получателя
* @param {number} senderId - ID отправителя
* @param {number} recipientId - ID получателя
* @returns {Object} { canSend: boolean, errorMessage?: string }
*/
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
// Проверяем базовое право на отправку сообщений
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
return {
canSend: false,
errorMessage: 'У вас нет права на отправку сообщений'
};
}
// Собственный чат - всегда разрешен (для ИИ ассистента)
if (senderId === recipientId) {
return { canSend: true };
}
// USER и READONLY могут писать только EDITOR
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
return { canSend: true };
}
// EDITOR может писать всем (USER, READONLY, EDITOR)
if (senderRole === 'editor') {
return { canSend: true };
}
// USER и READONLY НЕ могут писать друг другу
if ((senderRole === 'user' || senderRole === 'readonly') &&
(recipientRole === 'user' || recipientRole === 'readonly')) {
return {
canSend: false,
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
};
}
// Остальные случаи запрещены
return {
canSend: false,
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
};
}
// Экспорты для CommonJS (Node.js)
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}
// ES модули для Frontend
export {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
// CommonJS для Backend
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
ROLES,
PERMISSIONS,
PERMISSIONS_MAP,
hasPermission,
getPermissionsForRole,
hasAnyPermission,
hasAllPermissions,
getRoleDescription,
canSendMessage
};
}

0
scripts/ssh-key-server.js Executable file → Normal file
View File

View File

@@ -22,8 +22,7 @@ README*
.git/
.gitignore
# Зависимости (будут установлены в контейнере)
node_modules/
# Логи установки
npm-debug.log*
yarn-debug.log*
yarn-error.log*