15a03a77fd
Смена архитектуры с бизнес-бота на Bot API (команды со слешем) на личный юзербот на GramJS/MTProto с управлением через компаньон-бота. Возможности: - antidelete — кэш входящих в личке, восстановление удалённых «у всех» - onetime — перехват «просмотр один раз» фото/видео до истечения ссылки - локальное хранилище node:sqlite + шифрование AES-256-GCM, чистка по сроку - компаньон-бот (grammY): инлайн-панель, лента с пагинацией, выдача медиа, доступ только владельцу по OWNER_ID Устройство: - core/ — crypto, db, media, loader, registry, logger - userbot/ — MTProto-клиент из строки сессии, подписка на события - modules/ — фичи как модули с хуками setup/onMessage/onEdited/onDeleted - bot/ — компаньон-бот (единственный UI) - scripts/login.js — генерация строки сессии Удалён старый код Bot API (commands/, handlers/, middlewares/, dispatcher, store). Обновлены README и .env.example. Hcrgram/ (сторонний референс) добавлен в .gitignore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
48 lines
1.7 KiB
JavaScript
48 lines
1.7 KiB
JavaScript
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';
|
|
|
|
import { config } from '../config.js';
|
|
|
|
const ALGORITHM = 'aes-256-gcm';
|
|
const IV_LEN = 12;
|
|
const TAG_LEN = 16;
|
|
|
|
let keyCache = null;
|
|
|
|
/**
|
|
* Ключ из ENCRYPTION_KEY. Принимаем как 64-символьный hex (готовые 32 байта),
|
|
* так и произвольную парольную фразу — её растягиваем scrypt до 32 байт.
|
|
*/
|
|
function getKey() {
|
|
if (keyCache) return keyCache;
|
|
const raw = config.encryptionKey();
|
|
if (/^[0-9a-f]{64}$/i.test(raw)) {
|
|
keyCache = Buffer.from(raw, 'hex');
|
|
} else {
|
|
keyCache = scryptSync(raw, 'telegrambusiness/v1', 32);
|
|
}
|
|
return keyCache;
|
|
}
|
|
|
|
/**
|
|
* Шифрует буфер. Формат на выходе: [iv(12)][tag(16)][ciphertext].
|
|
* Так весь артефакт самодостаточен — расшифровка не требует внешних метаданных.
|
|
*/
|
|
export function encrypt(plaintext) {
|
|
const iv = randomBytes(IV_LEN);
|
|
const cipher = createCipheriv(ALGORITHM, getKey(), iv);
|
|
const data = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
return Buffer.concat([iv, cipher.getAuthTag(), data]);
|
|
}
|
|
|
|
export function decrypt(payload) {
|
|
const iv = payload.subarray(0, IV_LEN);
|
|
const tag = payload.subarray(IV_LEN, IV_LEN + TAG_LEN);
|
|
const data = payload.subarray(IV_LEN + TAG_LEN);
|
|
const decipher = createDecipheriv(ALGORITHM, getKey(), iv);
|
|
decipher.setAuthTag(tag);
|
|
return Buffer.concat([decipher.update(data), decipher.final()]);
|
|
}
|
|
|
|
export const encryptString = (text) => encrypt(Buffer.from(text, 'utf8')).toString('base64');
|
|
export const decryptString = (b64) => decrypt(Buffer.from(b64, 'base64')).toString('utf8');
|