diff --git a/src/entity.ts b/src/entity.ts index 19f1aad..cab674b 100644 --- a/src/entity.ts +++ b/src/entity.ts @@ -15,7 +15,7 @@ export function encrypt(entity: any): any { let options: ExtendedColumnOptions = columnMetadata.options; let encrypt = options.encrypt; if ( - encrypt && + encrypt && !(encrypt?.encryptionPredicate && !encrypt?.encryptionPredicate(entity)) && mode === 'regular' && (encrypt.looseMatching || entity.constructor === target) ) { @@ -43,8 +43,8 @@ export function decrypt(entity: any): any { let options: ExtendedColumnOptions = columnMetadata.options; let encrypt = options.encrypt; if ( - encrypt && - mode === 'regular' && + encrypt && !(encrypt?.encryptionPredicate && !encrypt?.encryptionPredicate(entity)) && + mode === "regular" && (encrypt.looseMatching || entity.constructor === target) ) { if (entity[propertyName]) { diff --git a/src/options/EncryptionOptions.ts b/src/options/EncryptionOptions.ts index b213356..d237816 100644 --- a/src/options/EncryptionOptions.ts +++ b/src/options/EncryptionOptions.ts @@ -5,4 +5,5 @@ export interface EncryptionOptions { iv?: string; //// For testing mainly. authTagLength?: number; looseMatching?: boolean; + encryptionPredicate?: (entity: any) => boolean; } diff --git a/test/encryption-predicate.test.ts b/test/encryption-predicate.test.ts new file mode 100644 index 0000000..78cd7d7 --- /dev/null +++ b/test/encryption-predicate.test.ts @@ -0,0 +1,46 @@ +import { expect } from "chai"; +import { encrypt, decrypt } from "../src/entity"; +import { getConnection } from "./utils"; +import ColumnOptionsEntity4 from "./entities/ColumnOptionsEntity4"; + +describe("Column Options - Encryption Predicate", function () { + this.timeout(10000); + + before(async function () { + await getConnection(); + }); + + it("should encrypt", function () { + let result = new ColumnOptionsEntity4(); + result.enablePredicate = true; + result.secret = "test"; + encrypt(result); + expect(result.secret).to.equal( + "/1rBkZBCSx2I+UGe+UmuVhKzmHsDDv0EvRtMBFiaE3A=" + ); + }); + + it("should not encrypt", function () { + let result = new ColumnOptionsEntity4(); + result.enablePredicate = false; + result.secret = "test"; + encrypt(result); + expect(result.secret).to.equal("test"); + }); + + it("should decrypt", function () { + let result = new ColumnOptionsEntity4(); + result.enablePredicate = true; + result.secret = "/1rBkZBCSx2I+UGe+UmuVhKzmHsDDv0EvRtMBFiaE3A="; + decrypt(result); + expect(result.secret).to.equal("test"); + }); + + it("should not decrypt", function () { + let result = new ColumnOptionsEntity4(); + result.enablePredicate = false; + result.secret = "test"; + decrypt(result); + expect(result.secret).to.equal("test"); + }); +}); diff --git a/test/entities/ColumnOptionsEntity4.ts b/test/entities/ColumnOptionsEntity4.ts new file mode 100644 index 0000000..99393f8 --- /dev/null +++ b/test/entities/ColumnOptionsEntity4.ts @@ -0,0 +1,25 @@ +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from "typeorm"; +import { ExtendedColumnOptions } from "../../src/options"; + +@Entity() +export default class ColumnOptionsEntity4 extends BaseEntity { + @PrimaryGeneratedColumn() + id: number; + + @Column({ type: "boolean" }) + enablePredicate: boolean; + + @Column({ + type: "varchar", + nullable: false, + encrypt: { + key: "e41c966f21f9e1577802463f8924e6a3fe3e9751f201304213b2f845d8841d61", + algorithm: "aes-256-cbc", + ivLength: 16, + iv: "ff5ac19190424b1d88f9419ef949ae56", + encryptionPredicate: (entity: ColumnOptionsEntity4) => + entity.enablePredicate, + }, + }) + secret: string; +} diff --git a/tsconfig.json b/tsconfig.json index 335570c..93f5e91 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,6 +20,6 @@ "declaration": true, "downlevelIteration": true }, - "include": ["src"], + "include": ["src", "test"], "exclude": ["tmp", "temp", "lib", "node_modules"] }