2026-08-09 19:16:52 +03:00
|
|
|
import { fileURLToPath } from 'node:url';
|
2026-08-09 16:53:38 +03:00
|
|
|
|
2026-08-09 19:16:52 +03:00
|
|
|
const req = (name) => {
|
|
|
|
|
const value = process.env[name];
|
|
|
|
|
if (!value) throw new Error(`${name} не задан в .env (см. .env.example).`);
|
|
|
|
|
return value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const num = (name) => {
|
|
|
|
|
const value = Number(process.env[name]);
|
|
|
|
|
if (!Number.isInteger(value)) throw new Error(`${name} должен быть целым числом.`);
|
|
|
|
|
return value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Конфиг MTProto-юзербота. api_id/api_hash берутся на https://my.telegram.org,
|
|
|
|
|
* строка сессии генерируется скриптом login (npm run login) и кладётся в .env.
|
|
|
|
|
* Всё, что чувствительно (сессия, ключ), живёт только в .env и никуда не уходит.
|
|
|
|
|
*/
|
2026-08-09 16:53:38 +03:00
|
|
|
export const config = {
|
2026-08-09 19:16:52 +03:00
|
|
|
// Доступ к MTProto.
|
|
|
|
|
apiId: () => num('API_ID'),
|
|
|
|
|
apiHash: () => req('API_HASH'),
|
|
|
|
|
session: process.env.SESSION ?? '',
|
|
|
|
|
|
|
|
|
|
// Компаньон-бот (@BotFather) — единственный UI юзербота.
|
|
|
|
|
botToken: () => req('BOT_TOKEN'),
|
|
|
|
|
// Telegram id владельца: только он управляет ботом и получает перехваты.
|
|
|
|
|
ownerId: () => num('OWNER_ID'),
|
|
|
|
|
|
|
|
|
|
// Ключ шифрования локального хранилища (32+ байта, hex или ascii).
|
|
|
|
|
encryptionKey: () => req('ENCRYPTION_KEY'),
|
|
|
|
|
|
|
|
|
|
// Сколько дней держать перехваченное, прежде чем чистить (0 — бессрочно).
|
|
|
|
|
retentionDays: Number(process.env.RETENTION_DAYS ?? 30),
|
|
|
|
|
|
|
|
|
|
// Качать ли медиа входящих сразу (нужно, чтобы восстанавливать удалённые
|
|
|
|
|
// картинки/видео — при удалении ссылка на файл уже мертва). Ест диск.
|
|
|
|
|
cacheMedia: process.env.CACHE_MEDIA !== '0',
|
|
|
|
|
|
2026-08-09 16:53:38 +03:00
|
|
|
dataDir: new URL('../data/', import.meta.url),
|
2026-08-09 19:16:52 +03:00
|
|
|
mediaDir: new URL('../data/media/', import.meta.url),
|
|
|
|
|
logLevel: process.env.LOG_LEVEL ?? 'info',
|
2026-08-09 16:53:38 +03:00
|
|
|
};
|
|
|
|
|
|
2026-08-09 19:16:52 +03:00
|
|
|
export const dataPath = () => fileURLToPath(config.dataDir);
|
|
|
|
|
export const mediaPath = () => fileURLToPath(config.mediaDir);
|
|
|
|
|
|
|
|
|
|
/** Проверяем всё, что нужно для старта, одним махом — понятная ошибка вместо падения в рантайме. */
|
2026-08-09 16:53:38 +03:00
|
|
|
export function assertConfig() {
|
2026-08-09 19:16:52 +03:00
|
|
|
config.apiId();
|
|
|
|
|
config.apiHash();
|
|
|
|
|
config.botToken();
|
|
|
|
|
config.ownerId();
|
|
|
|
|
const key = config.encryptionKey();
|
|
|
|
|
if (Buffer.from(key, key.match(/^[0-9a-f]+$/i) ? 'hex' : 'utf8').length < 32) {
|
|
|
|
|
throw new Error('ENCRYPTION_KEY должен быть не короче 32 байт (64 hex-символа).');
|
2026-08-09 16:53:38 +03:00
|
|
|
}
|
2026-08-09 19:16:52 +03:00
|
|
|
if (!config.session) {
|
|
|
|
|
throw new Error('SESSION пуст. Выполните: npm run login — и вставьте строку в .env.');
|
2026-08-09 16:53:38 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-09 19:16:52 +03:00
|
|
|
export const isOwner = (id) => Number(id) === config.ownerId();
|