@24hr/seqcryptor
Advanced tools
| import { DataTypes, Model, Sequelize } from 'sequelize'; | ||
| import { getSequlize } from './db'; | ||
| import { seqCryptor } from '../'; | ||
| describe('Encrypt', () => { | ||
| let sequelize: Sequelize; | ||
| beforeEach(async () => { | ||
| sequelize = await getSequlize(); | ||
| }); | ||
| it('Can update an object and it gets encrypted', async () => { | ||
| const encryptor = seqCryptor('_SUPER_SECRET_KEY_WITH_32_BYTES_'); | ||
| class User extends Model { | ||
| public info!: any; | ||
| public data!: any; | ||
| public guid!: string; | ||
| } | ||
| User.init({ | ||
| guid: { | ||
| allowNull: false, | ||
| unique: true, | ||
| type: DataTypes.UUID, | ||
| defaultValue: DataTypes.UUIDV4, | ||
| }, | ||
| info: encryptor({ | ||
| type: DataTypes.JSONB, | ||
| field: 'info', | ||
| defaultValue: {}, | ||
| }), | ||
| data: encryptor({ | ||
| type: DataTypes.JSONB, | ||
| field: 'data', | ||
| defaultValue: {}, | ||
| }), | ||
| }, { | ||
| sequelize, | ||
| paranoid: false, | ||
| }); | ||
| await User.sync(); | ||
| const user = await User.create({ data: { foo: 1 }, name: 'bar' }); | ||
| const userParsed = await User.findOne({ where: { guid: user.guid } }); | ||
| expect(userParsed!.info).toEqual({}); | ||
| expect(userParsed!.data).toEqual({ foo: 1 }); | ||
| }); | ||
| }); | ||
+1
-1
| import { DataTypes } from 'sequelize'; | ||
| import { ModelAttributeColumnOptions } from 'sequelize/types'; | ||
| export declare const seqCryptor: (secret: string) => (options: ModelAttributeColumnOptionsWithName) => ModelAttributeColumnOptions; | ||
| export declare const decrypt: (secret: string, rawData: string, returnRawOnUnecrypted?: boolean) => string; | ||
| export declare const decrypt: (secret: string, rawData: string, returnRawOnUnecrypted?: boolean, defaultValue?: any) => string; | ||
| export declare const encrypt: (secret: string, value: string) => string; | ||
@@ -6,0 +6,0 @@ export interface ModelAttributeColumnOptionsWithName extends ModelAttributeColumnOptions { |
+11
-3
@@ -22,5 +22,8 @@ "use strict"; | ||
| } | ||
| if (options.defaultValue && (options.type === sequelize_1.DataTypes.JSON || options.type === sequelize_1.DataTypes.JSONB)) { | ||
| options.defaultValue = JSON.stringify(options.defaultValue); | ||
| } | ||
| return Object.assign(Object.assign({}, options), { type: options.baseType || sequelize_1.DataTypes.STRING, get() { | ||
| const rawData = this.getDataValue(options.field); | ||
| const decryptedData = (0, exports.decrypt)(secret, rawData, options.returnRawOnUnecrypted); | ||
| const decryptedData = (0, exports.decrypt)(secret, rawData, options.returnRawOnUnecrypted, options.defaultValue); | ||
| if (options.type === sequelize_1.DataTypes.JSONB || options.type === sequelize_1.DataTypes.JSON) { | ||
@@ -43,5 +46,10 @@ return JSON.parse(decryptedData); | ||
| exports.seqCryptor = seqCryptor; | ||
| const decrypt = (secret, rawData, returnRawOnUnecrypted = false) => { | ||
| const decrypt = (secret, rawData, returnRawOnUnecrypted = false, defaultValue) => { | ||
| try { | ||
| const [rawValue, initVector] = rawData.split(ivSeparator); | ||
| let [rawValue, initVector] = rawData.split(ivSeparator); | ||
| // If we cant find an initVector and the value we got is the defaultValue, it provably means that | ||
| // the database doesnt contain anything, so we can return the defaultValue as cleartext | ||
| if (!initVector && rawValue === defaultValue) { | ||
| return defaultValue; | ||
| } | ||
| const decipher = crypto_1.default.createDecipheriv(algorithm, secret, Buffer.from(initVector, 'base64')); | ||
@@ -48,0 +56,0 @@ let decryptedData = decipher.update(rawValue, 'base64', 'utf-8'); |
+1
-1
| { | ||
| "name": "@24hr/seqcryptor", | ||
| "version": "0.8.5", | ||
| "version": "0.8.6", | ||
| "description": "", | ||
@@ -5,0 +5,0 @@ "main": "build/index.js", |
+14
-4
@@ -26,2 +26,6 @@ import crypto from 'crypto'; | ||
| if (options.defaultValue && (options.type === DataTypes.JSON || options.type === DataTypes.JSONB)) { | ||
| options.defaultValue = JSON.stringify(options.defaultValue); | ||
| } | ||
| return { | ||
@@ -32,3 +36,3 @@ ...options, | ||
| const rawData = this.getDataValue(options.field); | ||
| const decryptedData = decrypt(secret, rawData, options.returnRawOnUnecrypted); | ||
| const decryptedData = decrypt(secret, rawData, options.returnRawOnUnecrypted, options.defaultValue); | ||
| if (options.type === DataTypes.JSONB || options.type === DataTypes.JSON) { | ||
@@ -39,3 +43,3 @@ return JSON.parse(decryptedData); | ||
| }, | ||
| set (value: string) { | ||
| set (value: any) { | ||
| let parsedValue = value; | ||
@@ -55,5 +59,11 @@ if (options.type === DataTypes.JSONB || options.type === DataTypes.JSON) { | ||
| export const decrypt = (secret: string, rawData: string, returnRawOnUnecrypted: boolean = false): string => { | ||
| export const decrypt = (secret: string, rawData: string, returnRawOnUnecrypted: boolean = false, defaultValue?: any): string => { | ||
| try { | ||
| const [rawValue, initVector] = rawData.split(ivSeparator); | ||
| let [rawValue, initVector]: string[] = rawData.split(ivSeparator); | ||
| // If we cant find an initVector and the value we got is the defaultValue, it provably means that | ||
| // the database doesnt contain anything, so we can return the defaultValue as cleartext | ||
| if (!initVector && rawValue === defaultValue) { | ||
| return defaultValue; | ||
| } | ||
| const decipher = crypto.createDecipheriv(algorithm, secret, Buffer.from(initVector, 'base64')); | ||
@@ -60,0 +70,0 @@ let decryptedData = decipher.update(rawValue, 'base64', 'utf-8'); |
27844
10.09%15
7.14%520
12.8%