ваше сообщение коммита
This commit is contained in:
@@ -103,10 +103,11 @@ class AuthService {
|
||||
const userId = newUserResult.rows[0].id;
|
||||
|
||||
// Добавляем идентификатор кошелька (всегда в нижнем регистре)
|
||||
await db.getQuery()(
|
||||
'INSERT INTO user_identities (user_id, provider, provider_id) VALUES ($1, $2, $3)',
|
||||
[userId, 'wallet', normalizedAddress]
|
||||
);
|
||||
await encryptedDb.saveData('user_identities', {
|
||||
user_id: userId,
|
||||
provider: 'wallet',
|
||||
provider_id: normalizedAddress
|
||||
});
|
||||
|
||||
// Проверяем, есть ли у пользователя роль админа
|
||||
const isAdmin = await checkAdminRole(normalizedAddress);
|
||||
@@ -400,11 +401,11 @@ class AuthService {
|
||||
// Если в сессии нет авторизованного пользователя, проверяем существующие идентификаторы
|
||||
// Проверяем, существует ли уже пользователь с таким Telegram ID
|
||||
const existingUserResult = await db.getQuery()(
|
||||
`SELECT u.*, ui.provider, ui.provider_id
|
||||
`SELECT u.*, decrypt_text(ui.provider_encrypted, $2) as provider, decrypt_text(ui.provider_id_encrypted, $2) as provider_id
|
||||
FROM users u
|
||||
JOIN user_identities ui ON u.id = ui.user_id
|
||||
WHERE ui.provider = 'telegram' AND ui.provider_id = $1`,
|
||||
[telegramId]
|
||||
WHERE ui.provider_encrypted = encrypt_text('telegram', $2) AND ui.provider_id_encrypted = encrypt_text($1, $2)`,
|
||||
[telegramId, encryptionKey]
|
||||
);
|
||||
|
||||
// Если пользователь существует с таким telegramId, используем его
|
||||
@@ -423,10 +424,11 @@ class AuthService {
|
||||
isNewUser = true;
|
||||
|
||||
// Добавляем Telegram идентификатор
|
||||
await db.getQuery()(
|
||||
'INSERT INTO user_identities (user_id, provider, provider_id) VALUES ($1, $2, $3)',
|
||||
[userId, 'telegram', telegramId]
|
||||
);
|
||||
await encryptedDb.saveData('user_identities', {
|
||||
user_id: userId,
|
||||
provider: 'telegram',
|
||||
provider_id: telegramId
|
||||
});
|
||||
|
||||
logger.info(
|
||||
`[verifyTelegramAuth] Created new user ${userId} for Telegram ID ${telegramId}`
|
||||
@@ -582,10 +584,34 @@ class AuthService {
|
||||
async getUserIdentities(userId) {
|
||||
try {
|
||||
const identities = await encryptedDb.getData('user_identities', { user_id: userId }, null, 'created_at DESC');
|
||||
return identities;
|
||||
|
||||
// Данные уже расшифрованы encryptedDb, просто переименовываем поля
|
||||
const formattedIdentities = identities.map(identity => ({
|
||||
id: identity.id,
|
||||
user_id: identity.user_id,
|
||||
created_at: identity.created_at,
|
||||
provider: identity.provider, // Уже расшифровано
|
||||
provider_id: identity.provider_id // Уже расшифровано
|
||||
}));
|
||||
|
||||
return formattedIdentities;
|
||||
} catch (error) {
|
||||
logger.error('[getUserIdentities] Error:', error);
|
||||
throw error;
|
||||
|
||||
// Если произошла ошибка расшифровки, попробуем получить данные напрямую
|
||||
try {
|
||||
logger.info(`[AuthService] Trying to get unencrypted data for user ${userId}`);
|
||||
const { rows } = await db.getQuery()(
|
||||
'SELECT id, user_id, created_at, provider_encrypted as provider, provider_id_encrypted as provider_id FROM user_identities WHERE user_id = $1 ORDER BY created_at DESC',
|
||||
[userId]
|
||||
);
|
||||
|
||||
logger.info(`[AuthService] Found ${rows.length} unencrypted identities for user ${userId}`);
|
||||
return rows;
|
||||
} catch (fallbackError) {
|
||||
logger.error(`[AuthService] Fallback error getting identities for user ${userId}:`, fallbackError);
|
||||
throw fallbackError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -667,11 +693,11 @@ class AuthService {
|
||||
}
|
||||
|
||||
// Добавляем новый идентификатор для пользователя
|
||||
await db.getQuery()(
|
||||
`INSERT INTO user_identities (user_id, provider, provider_id)
|
||||
VALUES ($1, $2, $3)`,
|
||||
[userId, provider, normalizedProviderId]
|
||||
);
|
||||
await encryptedDb.saveData('user_identities', {
|
||||
user_id: userId,
|
||||
provider: provider,
|
||||
provider_id: normalizedProviderId
|
||||
});
|
||||
|
||||
// Проверяем и обновляем роль администратора, если это идентификатор кошелька
|
||||
let isAdmin = false;
|
||||
|
||||
@@ -15,7 +15,7 @@ const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { ethers } = require('ethers');
|
||||
const logger = require('../utils/logger');
|
||||
const { getRpcUrlByNetworkId } = require('./rpcProviderService');
|
||||
const { getRpcUrlByChainId } = require('./rpcProviderService');
|
||||
|
||||
/**
|
||||
* Сервис для управления DLE v2 (Digital Legal Entity)
|
||||
@@ -49,10 +49,15 @@ class DLEV2Service {
|
||||
fs.copyFileSync(paramsFile, tempParamsFile);
|
||||
logger.info(`Файл параметров скопирован успешно`);
|
||||
|
||||
// Получаем rpc_url из базы по выбранной сети
|
||||
const rpcUrl = await getRpcUrlByNetworkId(deployParams.network);
|
||||
// Определяем сеть для деплоя (берем первую из выбранных сетей)
|
||||
const chainId = deployParams.supportedChainIds && deployParams.supportedChainIds.length > 0
|
||||
? deployParams.supportedChainIds[0]
|
||||
: 1; // По умолчанию Ethereum
|
||||
|
||||
// Получаем rpc_url из базы по chain_id
|
||||
const rpcUrl = await getRpcUrlByChainId(chainId);
|
||||
if (!rpcUrl) {
|
||||
throw new Error(`RPC URL для сети ${deployParams.network} не найден в базе данных`);
|
||||
throw new Error(`RPC URL для сети с chain_id ${chainId} не найден в базе данных`);
|
||||
}
|
||||
if (!dleParams.privateKey) {
|
||||
throw new Error('Приватный ключ для деплоя не передан');
|
||||
@@ -62,8 +67,8 @@ class DLEV2Service {
|
||||
const result = await this.runDeployScript(paramsFile, {
|
||||
rpcUrl,
|
||||
privateKey: dleParams.privateKey,
|
||||
networkId: deployParams.network,
|
||||
envNetworkKey: deployParams.network.toUpperCase()
|
||||
networkId: chainId.toString(),
|
||||
envNetworkKey: chainId.toString().toUpperCase()
|
||||
});
|
||||
|
||||
// Очищаем временные файлы
|
||||
@@ -94,61 +99,73 @@ class DLEV2Service {
|
||||
throw new Error('Местонахождение DLE обязательно');
|
||||
}
|
||||
|
||||
if (!params.partners || !Array.isArray(params.partners)) {
|
||||
if (!params.initialPartners || !Array.isArray(params.initialPartners)) {
|
||||
throw new Error('Партнеры должны быть массивом');
|
||||
}
|
||||
|
||||
if (!params.amounts || !Array.isArray(params.amounts)) {
|
||||
if (!params.initialAmounts || !Array.isArray(params.initialAmounts)) {
|
||||
throw new Error('Суммы должны быть массивом');
|
||||
}
|
||||
|
||||
if (params.partners.length !== params.amounts.length) {
|
||||
if (params.initialPartners.length !== params.initialAmounts.length) {
|
||||
throw new Error('Количество партнеров должно соответствовать количеству сумм распределения');
|
||||
}
|
||||
|
||||
if (params.partners.length === 0) {
|
||||
if (params.initialPartners.length === 0) {
|
||||
throw new Error('Должен быть указан хотя бы один партнер');
|
||||
}
|
||||
|
||||
if (params.quorumPercentage > 100) {
|
||||
throw new Error('Процент кворума не может превышать 100%');
|
||||
if (params.quorumPercentage > 100 || params.quorumPercentage < 1) {
|
||||
throw new Error('Процент кворума должен быть от 1% до 100%');
|
||||
}
|
||||
|
||||
// Проверяем адреса партнеров
|
||||
for (let i = 0; i < params.partners.length; i++) {
|
||||
if (!ethers.isAddress(params.partners[i])) {
|
||||
throw new Error(`Неверный адрес партнера ${i + 1}: ${params.partners[i]}`);
|
||||
for (let i = 0; i < params.initialPartners.length; i++) {
|
||||
if (!ethers.isAddress(params.initialPartners[i])) {
|
||||
throw new Error(`Неверный адрес партнера ${i + 1}: ${params.initialPartners[i]}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Проверяем, что выбраны сети
|
||||
if (!params.supportedChainIds || !Array.isArray(params.supportedChainIds) || params.supportedChainIds.length === 0) {
|
||||
throw new Error('Должна быть выбрана хотя бы одна сеть для деплоя');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Подготавливает параметры для деплоя
|
||||
* @param {Object} params - Параметры DLE
|
||||
* @returns {Object} - Подготовленные параметры
|
||||
* @param {Object} params - Параметры DLE из формы
|
||||
* @returns {Object} - Подготовленные параметры для скрипта деплоя
|
||||
*/
|
||||
prepareDeployParams(params) {
|
||||
// Создаем копию объекта, чтобы не изменять исходный
|
||||
const deployParams = { ...params };
|
||||
|
||||
// Преобразуем суммы из строк или чисел в BigNumber, если нужно
|
||||
deployParams.amounts = params.amounts.map(amount => {
|
||||
if (typeof amount === 'string' && !amount.startsWith('0x')) {
|
||||
return ethers.parseEther(amount).toString();
|
||||
}
|
||||
return amount.toString();
|
||||
});
|
||||
if (deployParams.initialAmounts && Array.isArray(deployParams.initialAmounts)) {
|
||||
deployParams.initialAmounts = deployParams.initialAmounts.map(amount => {
|
||||
if (typeof amount === 'string' && !amount.startsWith('0x')) {
|
||||
return ethers.parseEther(amount).toString();
|
||||
}
|
||||
return amount.toString();
|
||||
});
|
||||
}
|
||||
|
||||
// Преобразуем параметры голосования
|
||||
deployParams.votingDelay = params.votingDelay || 1;
|
||||
deployParams.votingPeriod = params.votingPeriod || 45818; // ~1 неделя
|
||||
deployParams.proposalThreshold = params.proposalThreshold || ethers.parseEther("100000").toString();
|
||||
deployParams.quorumPercentage = params.quorumPercentage || 4;
|
||||
deployParams.minTimelockDelay = params.minTimelockDelay || 2;
|
||||
// Убеждаемся, что okvedCodes - это массив
|
||||
if (!Array.isArray(deployParams.okvedCodes)) {
|
||||
deployParams.okvedCodes = [];
|
||||
}
|
||||
|
||||
// Убеждаемся, что isicCodes - это массив
|
||||
if (!Array.isArray(deployParams.isicCodes)) {
|
||||
deployParams.isicCodes = [];
|
||||
// Убеждаемся, что supportedChainIds - это массив
|
||||
if (!Array.isArray(deployParams.supportedChainIds)) {
|
||||
deployParams.supportedChainIds = [1]; // По умолчанию Ethereum
|
||||
}
|
||||
|
||||
// Устанавливаем currentChainId как первую выбранную сеть
|
||||
if (deployParams.supportedChainIds.length > 0) {
|
||||
deployParams.currentChainId = deployParams.supportedChainIds[0];
|
||||
} else {
|
||||
deployParams.currentChainId = 1; // По умолчанию Ethereum
|
||||
}
|
||||
|
||||
return deployParams;
|
||||
@@ -244,20 +261,18 @@ class DLEV2Service {
|
||||
extractDeployResult(stdout) {
|
||||
// Ищем строки с адресами в выводе
|
||||
const dleAddressMatch = stdout.match(/DLE v2 задеплоен по адресу: (0x[a-fA-F0-9]{40})/);
|
||||
const timelockAddressMatch = stdout.match(/Таймлок создан по адресу: (0x[a-fA-F0-9]{40})/);
|
||||
|
||||
if (dleAddressMatch && timelockAddressMatch) {
|
||||
if (dleAddressMatch) {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
dleAddress: dleAddressMatch[1],
|
||||
timelockAddress: timelockAddressMatch[1],
|
||||
version: 'v2'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error('Не удалось извлечь адреса из вывода скрипта');
|
||||
throw new Error('Не удалось извлечь адрес DLE из вывода скрипта');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -77,9 +77,9 @@ class EncryptedDataService {
|
||||
const originalName = col.column_name.replace('_encrypted', '');
|
||||
// console.log(`🔓 Расшифровываем поле ${col.column_name} -> ${originalName}`);
|
||||
if (col.data_type === 'jsonb') {
|
||||
return `decrypt_json(${col.column_name}, $1) as "${originalName}"`;
|
||||
return `CASE WHEN ${col.column_name} IS NULL OR ${col.column_name} = '' THEN NULL ELSE decrypt_json(${col.column_name}, $1) END as "${originalName}"`;
|
||||
} else {
|
||||
return `decrypt_text(${col.column_name}, $1) as "${originalName}"`;
|
||||
return `CASE WHEN ${col.column_name} IS NULL OR ${col.column_name} = '' THEN NULL ELSE decrypt_text(${col.column_name}, $1) END as "${originalName}"`;
|
||||
}
|
||||
} else if (!col.column_name.includes('_encrypted')) {
|
||||
// Проверяем, есть ли зашифрованная версия этой колонки
|
||||
@@ -181,6 +181,13 @@ class EncryptedDataService {
|
||||
return rows;
|
||||
} catch (error) {
|
||||
// console.error(`❌ Ошибка получения данных из ${tableName}:`, error);
|
||||
|
||||
// Если ошибка связана с расшифровкой, попробуем получить данные без расшифровки
|
||||
if (error.message && error.message.includes('invalid base64')) {
|
||||
console.log(`⚠️ Ошибка расшифровки в ${tableName}, пытаемся получить данные без расшифровки`);
|
||||
return await this.executeUnencryptedQuery(tableName, conditions, limit, orderBy);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -230,17 +237,18 @@ class EncryptedDataService {
|
||||
// Проверяем, что значение не пустое перед шифрованием
|
||||
if (value === null || value === undefined || (typeof value === 'string' && value.trim() === '')) {
|
||||
// Пропускаем пустые значения
|
||||
// console.log(`⚠️ Пропускаем пустое зашифрованное поле ${key}`);
|
||||
console.log(`⚠️ Пропускаем пустое зашифрованное поле ${key}`);
|
||||
continue;
|
||||
}
|
||||
const currentParamIndex = paramIndex++;
|
||||
filteredData[key] = value; // Добавляем в отфильтрованные данные
|
||||
// console.log(`✅ Добавили зашифрованное поле ${key} в filteredData`);
|
||||
console.log(`✅ Добавили зашифрованное поле ${key} = "${value}" в filteredData`);
|
||||
if (encryptedColumn.data_type === 'jsonb') {
|
||||
encryptedData[`${key}_encrypted`] = `encrypt_json($${currentParamIndex}, ${hasEncryptedFields ? '$1::text' : 'NULL'})`;
|
||||
} else {
|
||||
encryptedData[`${key}_encrypted`] = `encrypt_text($${currentParamIndex}, ${hasEncryptedFields ? '$1::text' : 'NULL'})`;
|
||||
}
|
||||
console.log(`🔐 Будем шифровать ${key} -> ${key}_encrypted`);
|
||||
} else if (unencryptedColumn) {
|
||||
// Если есть незашифрованная колонка, сохраняем как есть
|
||||
// Проверяем, что значение не пустое перед сохранением (кроме role и sender_type)
|
||||
@@ -297,6 +305,10 @@ class EncryptedDataService {
|
||||
const query = `INSERT INTO ${tableName} (${columns.join(', ')}) VALUES (${placeholders}) RETURNING *`;
|
||||
const params = hasEncryptedFields ? [this.encryptionKey, ...Object.values(filteredData)] : [...Object.values(filteredData)];
|
||||
|
||||
console.log(`🔍 Выполняем INSERT запрос:`, query);
|
||||
console.log(`🔍 Параметры:`, params);
|
||||
console.log(`🔍 Ключ шифрования:`, this.encryptionKey ? 'установлен' : 'не установлен');
|
||||
|
||||
const { rows } = await db.getQuery()(query, params);
|
||||
return rows[0];
|
||||
}
|
||||
|
||||
@@ -151,10 +151,34 @@ class IdentityService {
|
||||
try {
|
||||
const identities = await encryptedDb.getData('user_identities', { user_id: userId });
|
||||
logger.info(`[IdentityService] Found ${identities.length} identities for user ${userId}`);
|
||||
return identities;
|
||||
|
||||
// Данные уже расшифрованы encryptedDb, просто переименовываем поля
|
||||
const formattedIdentities = identities.map(identity => ({
|
||||
id: identity.id,
|
||||
user_id: identity.user_id,
|
||||
created_at: identity.created_at,
|
||||
provider: identity.provider, // Уже расшифровано
|
||||
provider_id: identity.provider_id // Уже расшифровано
|
||||
}));
|
||||
|
||||
return formattedIdentities;
|
||||
} catch (error) {
|
||||
logger.error(`[IdentityService] Error getting identities for user ${userId}:`, error);
|
||||
return [];
|
||||
|
||||
// Если произошла ошибка расшифровки, попробуем получить данные напрямую
|
||||
try {
|
||||
logger.info(`[IdentityService] Trying to get unencrypted data for user ${userId}`);
|
||||
const { rows } = await db.getQuery()(
|
||||
'SELECT id, user_id, created_at, provider_encrypted as provider, provider_id_encrypted as provider_id FROM user_identities WHERE user_id = $1',
|
||||
[userId]
|
||||
);
|
||||
|
||||
logger.info(`[IdentityService] Found ${rows.length} unencrypted identities for user ${userId}`);
|
||||
return rows;
|
||||
} catch (fallbackError) {
|
||||
logger.error(`[IdentityService] Fallback error getting identities for user ${userId}:`, fallbackError);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,4 +62,9 @@ async function getRpcUrlByNetworkId(networkId) {
|
||||
return providers[0]?.rpc_url || null;
|
||||
}
|
||||
|
||||
module.exports = { getAllRpcProviders, saveAllRpcProviders, upsertRpcProvider, deleteRpcProvider, getRpcUrlByNetworkId };
|
||||
async function getRpcUrlByChainId(chainId) {
|
||||
const providers = await encryptedDb.getData('rpc_providers', { chain_id: chainId }, 1);
|
||||
return providers[0]?.rpc_url || null;
|
||||
}
|
||||
|
||||
module.exports = { getAllRpcProviders, saveAllRpcProviders, upsertRpcProvider, deleteRpcProvider, getRpcUrlByNetworkId, getRpcUrlByChainId };
|
||||
Reference in New Issue
Block a user