CognxSafeTrack
Claude Sonnet 4.6
refactor(worker): Sprint 2 — dead code removal and queue consolidation
37fb9ce Download scripts/db-ops/check_encryption.ts from safetrack/edtech: direct link, hf CLI and curl.
- Browser
- Download file 2.16 kB
-
https://huggingface.co/spaces/safetrack/edtech/resolve/main/scripts/db-ops/check_encryption.ts
- Command line
-
hf download hf://spaces/safetrack/edtech/scripts/db-ops/check_encryption.ts
-
curl -L -o check_encryption.ts https://huggingface.co/spaces/safetrack/edtech/resolve/main/scripts/db-ops/check_encryption.ts
2.16 kB
| /** | |
| * Diagnostic: vérifie si l'ENCRYPTION_SECRET actuel peut déchiffrer les secrets en DB. | |
| * | |
| * Usage: | |
| * ENCRYPTION_SECRET=<ta_cle_railway> DATABASE_URL=<prod_url> \ | |
| * npx ts-node apps/api/scratch/check_encryption.ts | |
| */ | |
| 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); | |