| |
| |
| |
| |
| |
| |
| |
|
|
| import 'dotenv/config'; |
| import { PrismaClient } from '@prisma/client'; |
| import crypto from 'crypto'; |
|
|
| const prisma = new PrismaClient(); |
| const SECRET = process.env.ENCRYPTION_SECRET || ''; |
|
|
| if (SECRET.length < 32) { |
| console.error('❌ ENCRYPTION_SECRET manquant ou trop court (min 32 chars)'); |
| process.exit(1); |
| } |
|
|
| function tryDecrypt(value: string): { ok: boolean; result: string } { |
| if (!value.startsWith('enc:')) return { ok: true, result: `[PLAINTEXT] ${value.slice(0, 20)}...` }; |
| const [, ivHex, encHex] = value.split(':'); |
| if (!ivHex || !encHex) return { ok: false, result: 'Format invalide' }; |
| try { |
| const iv = Buffer.from(ivHex, 'hex'); |
| const enc = Buffer.from(encHex, 'hex'); |
| const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(SECRET.slice(0, 32)), iv); |
| let dec = decipher.update(enc); |
| dec = Buffer.concat([dec, decipher.final()]); |
| const plain = dec.toString(); |
| return { ok: true, result: `${plain.slice(0, 6)}...${plain.slice(-4)} (len=${plain.length})` }; |
| } catch (err: any) { |
| return { ok: false, result: err.message }; |
| } |
| } |
|
|
| const FIELDS = ['systemUserToken', 'webhookSecret', 'openAiApiKey', 'googleAiApiKey'] as const; |
|
|
| async function check() { |
| const orgs = await prisma.organization.findMany({ |
| select: { id: true, name: true, systemUserToken: true, webhookSecret: true, openAiApiKey: true, googleAiApiKey: true } |
| }); |
|
|
| for (const org of orgs) { |
| console.log(`\n📦 Org: ${org.name} (${org.id})`); |
| for (const field of FIELDS) { |
| const val = (org as any)[field] as string | null; |
| if (!val) { console.log(` ${field}: (vide)`); continue; } |
| const { ok, result } = tryDecrypt(val); |
| console.log(` ${ok ? '✅' : '❌'} ${field}: ${result}`); |
| } |
| } |
| await prisma.$disconnect(); |
| } |
|
|
| check().catch(console.error); |
|
|