import { SQL, sql } from "drizzle-orm"; import { AnyPgColumn, customType } from "drizzle-orm/pg-core"; // Clé de chiffrement PGP récupérée depuis l'environnement const getPgpKey = () => process.env.PGP_ENCRYPTION_KEY || "default-pgp-key"; /** * Type personnalisé pour les données chiffrées PGP (stockées en bytea dans Postgres). * Le chiffrement est géré automatiquement à l'écriture (INSERT/UPDATE) via `toDriver`. * * **Pour que le déchiffrement soit automatique à la lecture (SELECT), il faut impérativement utiliser l'utilitaire * `withAutomaticPgpDecrypt` sur la colonne après la définition de la table. Attention à la consommation CPU et mémoire** * * @example * ```ts * export const users = pgTable('users', { * email: pgpEncrypted('email').notNull(), * }); * * // Activation du déchiffrement automatique * withAutomaticPgpDecrypt(users.email); * ``` */ export const pgpEncrypted = customType<{ data: string; driverData: Buffer }>({ dataType() { return "bytea"; }, toDriver(value: string): SQL { return sql`pgp_sym_encrypt(${value}, ${getPgpKey()})`; }, fromDriver(value: Buffer | string): string { if (typeof value === "string") return value; return value.toString(); }, }); /** * Utilitaire pour injecter le déchiffrement automatique dans une colonne. * Modifie la méthode getSQL de la colonne pour inclure pgp_sym_decrypt. */ export function withAutomaticPgpDecrypt(column: T): T { const originalGetSQL = column.getSQL.bind(column); column.getSQL = () => sql`pgp_sym_decrypt(${originalGetSQL()}, ${getPgpKey()})::text`.mapWith( column, ); return column; } /** * @deprecated Utiliser directement les colonnes de type pgpEncrypted qui gèrent maintenant le chiffrement automatiquement. */ export function pgpSymEncrypt(value: string | SQL, key: string | SQL) { return sql`pgp_sym_encrypt(${value}, ${key})`; } /** * @deprecated Utiliser directement les colonnes de type pgpEncrypted qui gèrent maintenant le déchiffrement automatiquement. */ export function pgpSymDecrypt( column: AnyPgColumn, key: string | SQL, ): SQL { return sql`pgp_sym_decrypt(${column}, ${key})::text`.mapWith( column, ) as SQL; }