diff --git a/backend/src/database/schemas/pgp.ts b/backend/src/database/schemas/pgp.ts new file mode 100644 index 0000000..cc514e8 --- /dev/null +++ b/backend/src/database/schemas/pgp.ts @@ -0,0 +1,60 @@ +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()})`.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})`.mapWith(column) as SQL; +}