@things-factory/shell 6.1.182 → 6.1.189
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/config.development.js +2 -0
- package/config/config.production.js +34 -33
- package/dist-server/index.d.ts +1 -0
- package/dist-server/index.js +1 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/middlewares/index.js +0 -3
- package/dist-server/middlewares/index.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/dist-server/typeorm/encrypt-transform.d.ts +2 -0
- package/dist-server/typeorm/encrypt-transform.js +39 -0
- package/dist-server/typeorm/encrypt-transform.js.map +1 -0
- package/dist-server/typeorm/encrypted-column.d.ts +1 -0
- package/dist-server/typeorm/encrypted-column.js +114 -0
- package/dist-server/typeorm/encrypted-column.js.map +1 -0
- package/dist-server/typeorm/get-data-encryption-key.d.ts +1 -0
- package/dist-server/typeorm/get-data-encryption-key.js +15 -0
- package/dist-server/typeorm/get-data-encryption-key.js.map +1 -0
- package/package.json +3 -3
- package/server/index.ts +1 -0
- package/server/middlewares/index.ts +0 -4
- package/server/typeorm/encrypt-transform.ts +44 -0
- package/server/typeorm/get-data-encryption-key.ts +13 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.encryptTransformer = void 0;
|
4
|
+
const crypto_1 = require("crypto");
|
5
|
+
const get_data_encryption_key_1 = require("./get-data-encryption-key");
|
6
|
+
const ALGORITHM = 'aes-256-cbc';
|
7
|
+
const KEY_LENGTH = 32;
|
8
|
+
const SALT_LENGTH = 16;
|
9
|
+
const IV_LENGTH = 16;
|
10
|
+
exports.encryptTransformer = {
|
11
|
+
to: (entityValue) => encrypt(entityValue),
|
12
|
+
from: (databaseValue) => decrypt(databaseValue) // DB에서 값을 가져올 때 복호화
|
13
|
+
};
|
14
|
+
function encrypt(text) {
|
15
|
+
if (!text) {
|
16
|
+
return null;
|
17
|
+
}
|
18
|
+
const iv = (0, crypto_1.randomBytes)(IV_LENGTH);
|
19
|
+
const cipher = (0, crypto_1.createCipheriv)(ALGORITHM, get_data_encryption_key_1.dataEncryptionKey, iv);
|
20
|
+
const encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()]);
|
21
|
+
return `${iv.toString('hex')}:${encrypted.toString('hex')}`;
|
22
|
+
}
|
23
|
+
function decrypt(text) {
|
24
|
+
if (!text) {
|
25
|
+
return null;
|
26
|
+
}
|
27
|
+
try {
|
28
|
+
const parts = text.split(':');
|
29
|
+
const iv = Buffer.from(parts.shift(), 'hex');
|
30
|
+
const encryptedText = Buffer.from(parts.join(':'), 'hex');
|
31
|
+
const decipher = (0, crypto_1.createDecipheriv)(ALGORITHM, get_data_encryption_key_1.dataEncryptionKey, iv);
|
32
|
+
return Buffer.concat([decipher.update(encryptedText), decipher.final()]).toString('utf8');
|
33
|
+
}
|
34
|
+
catch (err) {
|
35
|
+
console.error(`decryption for encrypted field failed in encryptTransformer`);
|
36
|
+
return null;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
//# sourceMappingURL=encrypt-transform.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"encrypt-transform.js","sourceRoot":"","sources":["../../server/typeorm/encrypt-transform.ts"],"names":[],"mappings":";;;AACA,mCAAkF;AAElF,uEAA6D;AAE7D,MAAM,SAAS,GAAG,aAAa,CAAA;AAC/B,MAAM,UAAU,GAAG,EAAE,CAAA;AACrB,MAAM,WAAW,GAAG,EAAE,CAAA;AACtB,MAAM,SAAS,GAAG,EAAE,CAAA;AAEP,QAAA,kBAAkB,GAAqB;IAClD,EAAE,EAAE,CAAC,WAAmB,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC;IACjD,IAAI,EAAE,CAAC,aAAqB,EAAE,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,oBAAoB;CAC7E,CAAA;AAED,SAAS,OAAO,CAAC,IAAY;IAC3B,IAAI,CAAC,IAAI,EAAE;QACT,OAAO,IAAI,CAAA;KACZ;IAED,MAAM,EAAE,GAAG,IAAA,oBAAW,EAAC,SAAS,CAAC,CAAA;IACjC,MAAM,MAAM,GAAG,IAAA,uBAAc,EAAC,SAAS,EAAE,2CAAiB,EAAE,EAAE,CAAC,CAAA;IAC/D,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IAE9E,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAA;AAC7D,CAAC;AAED,SAAS,OAAO,CAAC,IAAY;IAC3B,IAAI,CAAC,IAAI,EAAE;QACT,OAAO,IAAI,CAAA;KACZ;IAED,IAAI;QACF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC7B,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,KAAK,CAAC,CAAA;QAC5C,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAA;QACzD,MAAM,QAAQ,GAAG,IAAA,yBAAgB,EAAC,SAAS,EAAE,2CAAiB,EAAE,EAAE,CAAC,CAAA;QAEnE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;KAC1F;IAAC,OAAO,GAAG,EAAE;QACZ,OAAO,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAA;QAC5E,OAAO,IAAI,CAAA;KACZ;AACH,CAAC","sourcesContent":["import { ValueTransformer } from 'typeorm'\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'crypto'\n\nimport { dataEncryptionKey } from './get-data-encryption-key'\n\nconst ALGORITHM = 'aes-256-cbc'\nconst KEY_LENGTH = 32\nconst SALT_LENGTH = 16\nconst IV_LENGTH = 16\n\nexport const encryptTransformer: ValueTransformer = {\n to: (entityValue: string) => encrypt(entityValue), // DB에 저장하기 전에 암호화\n from: (databaseValue: string) => decrypt(databaseValue) // DB에서 값을 가져올 때 복호화\n}\n\nfunction encrypt(text: string): string {\n if (!text) {\n return null\n }\n\n const iv = randomBytes(IV_LENGTH)\n const cipher = createCipheriv(ALGORITHM, dataEncryptionKey, iv)\n const encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()])\n\n return `${iv.toString('hex')}:${encrypted.toString('hex')}`\n}\n\nfunction decrypt(text: string): string {\n if (!text) {\n return null\n }\n\n try {\n const parts = text.split(':')\n const iv = Buffer.from(parts.shift(), 'hex')\n const encryptedText = Buffer.from(parts.join(':'), 'hex')\n const decipher = createDecipheriv(ALGORITHM, dataEncryptionKey, iv)\n\n return Buffer.concat([decipher.update(encryptedText), decipher.final()]).toString('utf8')\n } catch (err) {\n console.error(`decryption for encrypted field failed in encryptTransformer`)\n return null\n }\n}\n"]}
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare function EncryptedColumn(): PropertyDecorator;
|
@@ -0,0 +1,114 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.EncryptedColumn = void 0;
|
4
|
+
const typeorm_1 = require("typeorm");
|
5
|
+
const ALGORITHM = 'aes-256-cbc';
|
6
|
+
const KEY_LENGTH = 32;
|
7
|
+
const SALT_LENGTH = 16;
|
8
|
+
const IV_LENGTH = 16;
|
9
|
+
function EncryptedColumn() {
|
10
|
+
return function (target, propertyName) {
|
11
|
+
(0, typeorm_1.Column)('text', { nullable: true })(target, propertyName);
|
12
|
+
const beforeHandlerName = `encrypt_${String(propertyName)}`;
|
13
|
+
const afterHandlerName = `decrypt_${String(propertyName)}`;
|
14
|
+
// BeforeInsert and BeforeUpdate logic
|
15
|
+
(0, typeorm_1.BeforeInsert)()(target, beforeHandlerName);
|
16
|
+
// getMetadataArgsStorage().entityListeners.push({
|
17
|
+
// target: target.constructor,
|
18
|
+
// propertyName: beforeHandlerName,
|
19
|
+
// type: 'before-insert'
|
20
|
+
// })
|
21
|
+
(0, typeorm_1.BeforeUpdate)()(target, beforeHandlerName);
|
22
|
+
// getMetadataArgsStorage().entityListeners.push({
|
23
|
+
// target: target.constructor,
|
24
|
+
// propertyName: beforeHandlerName,
|
25
|
+
// type: 'before-update'
|
26
|
+
// })
|
27
|
+
(0, typeorm_1.AfterLoad)()(target, afterHandlerName);
|
28
|
+
// getMetadataArgsStorage().entityListeners.push({
|
29
|
+
// target: target.constructor,
|
30
|
+
// propertyName: afterHandlerName,
|
31
|
+
// type: 'after-load'
|
32
|
+
// })
|
33
|
+
target[beforeHandlerName] = function () {
|
34
|
+
// TODO 암호화 로직
|
35
|
+
if (this[propertyName]) {
|
36
|
+
// const salt = randomBytes(16).toString('hex')
|
37
|
+
// const key = scryptSync(process.env.ENCRYPTION_KEY!, salt, 32)
|
38
|
+
// const iv = randomBytes(16)
|
39
|
+
// const cipher = createCipheriv(ALGORITHM, key, iv)
|
40
|
+
// const encrypted = Buffer.concat([cipher.update(this[propertyName]), cipher.final()])
|
41
|
+
// this[propertyName] = `${salt}.${iv.toString('hex')}.${encrypted.toString('hex')}`
|
42
|
+
}
|
43
|
+
};
|
44
|
+
target[afterHandlerName] = function () {
|
45
|
+
// TODO 복호화 로직
|
46
|
+
if (this[propertyName]) {
|
47
|
+
// const salt = randomBytes(16).toString('hex')
|
48
|
+
// const key = scryptSync(process.env.ENCRYPTION_KEY!, salt, 32)
|
49
|
+
// const iv = randomBytes(16)
|
50
|
+
// const cipher = createCipheriv(ALGORITHM, key, iv)
|
51
|
+
// const encrypted = Buffer.concat([cipher.update(this[propertyName]), cipher.final()])
|
52
|
+
// this[propertyName] = `${salt}.${iv.toString('hex')}.${encrypted.toString('hex')}`
|
53
|
+
}
|
54
|
+
};
|
55
|
+
};
|
56
|
+
}
|
57
|
+
exports.EncryptedColumn = EncryptedColumn;
|
58
|
+
// import { BeforeInsert, BeforeUpdate, Column, getMetadataArgsStorage } from 'typeorm'
|
59
|
+
// import { randomBytes, createCipheriv, createDecipheriv, scryptSync } from 'crypto'
|
60
|
+
// import { dataEncryptionKey } from './get-data-encryption-key'
|
61
|
+
// const ALGORITHM = 'aes-256-gcm'
|
62
|
+
// export function EncryptedColumn(): PropertyDecorator {
|
63
|
+
// return function (target: Object, propertyName: string | symbol) {
|
64
|
+
// Column("text", { nullable: true })(target, propertyName);
|
65
|
+
// const className = target.constructor.name;
|
66
|
+
// BeforeInsert()(target, "encryptField");
|
67
|
+
// BeforeUpdate()(target, "encryptField");
|
68
|
+
// getMetadataArgsStorage().entityListeners.push({
|
69
|
+
// target: className,
|
70
|
+
// propertyName: "encryptField",
|
71
|
+
// type: "beforeInsert"
|
72
|
+
// });
|
73
|
+
// getMetadataArgsStorage().entityListeners.push({
|
74
|
+
// target: className,
|
75
|
+
// propertyName: "encryptField",
|
76
|
+
// type: "beforeUpdate"
|
77
|
+
// });
|
78
|
+
// target["encryptField"] = function() {
|
79
|
+
// const salt = randomBytes(16).toString('hex');
|
80
|
+
// const key = scryptSync(dataEncryptionKey!, salt, 32);
|
81
|
+
// const iv = randomBytes(16);
|
82
|
+
// const cipher = createCipheriv(ALGORITHM, key, iv);
|
83
|
+
// const encrypted = Buffer.concat([cipher.update(this[propertyName as string]), cipher.final()]);
|
84
|
+
// this[propertyName as string] = `${salt}.${iv.toString('hex')}.${encrypted.toString('hex')}`;
|
85
|
+
// }
|
86
|
+
// // 원래의 프로퍼티 이름을 저장하는 변수를 선언
|
87
|
+
// const originalPropertyName = `_${String(propertyName)}`
|
88
|
+
// // 기본 컬럼 데코레이터
|
89
|
+
// Column('text', { nullable: true })(target, originalPropertyName)
|
90
|
+
// Object.defineProperty(target, propertyName, {
|
91
|
+
// get: function () {
|
92
|
+
// const [salt, ivHex, encryptedHex] = (this[originalPropertyName] || '').split('.')
|
93
|
+
// const key = scryptSync(dataEncryptionKey!, salt, 32)
|
94
|
+
// try {
|
95
|
+
// const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(ivHex, 'hex'))
|
96
|
+
// const decrypted = Buffer.concat([decipher.update(Buffer.from(encryptedHex, 'hex')), decipher.final()])
|
97
|
+
// return decrypted.toString()
|
98
|
+
// } catch (err) {
|
99
|
+
// console.error(`decryption for ${String(propertyName)} field failed`)
|
100
|
+
// return null
|
101
|
+
// }
|
102
|
+
// },
|
103
|
+
// set: function (value) {
|
104
|
+
// const salt = randomBytes(16).toString('hex')
|
105
|
+
// const key = scryptSync(dataEncryptionKey!, salt, 32)
|
106
|
+
// const iv = randomBytes(16)
|
107
|
+
// const cipher = createCipheriv(ALGORITHM, key, iv)
|
108
|
+
// const encrypted = Buffer.concat([cipher.update(value), cipher.final()])
|
109
|
+
// this[originalPropertyName] = `${salt}.${iv.toString('hex')}.${encrypted.toString('hex')}`
|
110
|
+
// }
|
111
|
+
// })
|
112
|
+
// }
|
113
|
+
// }
|
114
|
+
//# sourceMappingURL=encrypted-column.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"encrypted-column.js","sourceRoot":"","sources":["../../server/typeorm/encrypted-column.ts"],"names":[],"mappings":";;;AAAA,qCAA+F;AAI/F,MAAM,SAAS,GAAG,aAAa,CAAA;AAC/B,MAAM,UAAU,GAAG,EAAE,CAAA;AACrB,MAAM,WAAW,GAAG,EAAE,CAAA;AACtB,MAAM,SAAS,GAAG,EAAE,CAAA;AAEpB,SAAgB,eAAe;IAC7B,OAAO,UAAU,MAAc,EAAE,YAA6B;QAC5D,IAAA,gBAAM,EAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;QAExD,MAAM,iBAAiB,GAAG,WAAW,MAAM,CAAC,YAAY,CAAC,EAAE,CAAA;QAC3D,MAAM,gBAAgB,GAAG,WAAW,MAAM,CAAC,YAAY,CAAC,EAAE,CAAA;QAE1D,sCAAsC;QACtC,IAAA,sBAAY,GAAE,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;QACzC,kDAAkD;QAClD,gCAAgC;QAChC,qCAAqC;QACrC,0BAA0B;QAC1B,KAAK;QAEL,IAAA,sBAAY,GAAE,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;QACzC,kDAAkD;QAClD,gCAAgC;QAChC,qCAAqC;QACrC,0BAA0B;QAC1B,KAAK;QAEL,IAAA,mBAAS,GAAE,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;QACrC,kDAAkD;QAClD,gCAAgC;QAChC,oCAAoC;QACpC,uBAAuB;QACvB,KAAK;QAEL,MAAM,CAAC,iBAAiB,CAAC,GAAG;YAC1B,cAAc;YACd,IAAI,IAAI,CAAC,YAAY,CAAC,EAAE;gBACtB,+CAA+C;gBAC/C,gEAAgE;gBAChE,6BAA6B;gBAC7B,oDAAoD;gBACpD,uFAAuF;gBACvF,oFAAoF;aACrF;QACH,CAAC,CAAA;QAED,MAAM,CAAC,gBAAgB,CAAC,GAAG;YACzB,cAAc;YACd,IAAI,IAAI,CAAC,YAAY,CAAC,EAAE;gBACtB,+CAA+C;gBAC/C,gEAAgE;gBAChE,6BAA6B;gBAC7B,oDAAoD;gBACpD,uFAAuF;gBACvF,oFAAoF;aACrF;QACH,CAAC,CAAA;IACH,CAAC,CAAA;AACH,CAAC;AArDD,0CAqDC;AAED,uFAAuF;AACvF,qFAAqF;AACrF,gEAAgE;AAEhE,kCAAkC;AAElC,yDAAyD;AACzD,sEAAsE;AACtE,gEAAgE;AAEhE,iDAAiD;AAEjD,8CAA8C;AAC9C,8CAA8C;AAE9C,sDAAsD;AACtD,6BAA6B;AAC7B,wCAAwC;AACxC,+BAA+B;AAC/B,UAAU;AAEV,sDAAsD;AACtD,6BAA6B;AAC7B,wCAAwC;AACxC,+BAA+B;AAC/B,UAAU;AAEV,4CAA4C;AAC5C,wDAAwD;AACxD,gEAAgE;AAEhE,sCAAsC;AACtC,6DAA6D;AAC7D,0GAA0G;AAE1G,uGAAuG;AACvG,QAAQ;AAER,kCAAkC;AAClC,8DAA8D;AAE9D,qBAAqB;AACrB,uEAAuE;AAEvE,oDAAoD;AACpD,2BAA2B;AAC3B,4FAA4F;AAC5F,+DAA+D;AAE/D,gBAAgB;AAChB,yFAAyF;AACzF,mHAAmH;AAEnH,wCAAwC;AACxC,0BAA0B;AAC1B,iFAAiF;AACjF,wBAAwB;AACxB,YAAY;AACZ,WAAW;AACX,gCAAgC;AAChC,uDAAuD;AACvD,+DAA+D;AAE/D,qCAAqC;AACrC,4DAA4D;AAC5D,kFAAkF;AAElF,oGAAoG;AACpG,UAAU;AACV,SAAS;AACT,MAAM;AACN,IAAI","sourcesContent":["import { AfterLoad, BeforeInsert, BeforeUpdate, Column, getMetadataArgsStorage } from 'typeorm'\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'crypto'\nimport { dataEncryptionKey } from './get-data-encryption-key'\n\nconst ALGORITHM = 'aes-256-cbc'\nconst KEY_LENGTH = 32\nconst SALT_LENGTH = 16\nconst IV_LENGTH = 16\n\nexport function EncryptedColumn(): PropertyDecorator {\n return function (target: Object, propertyName: string | symbol) {\n Column('text', { nullable: true })(target, propertyName)\n\n const beforeHandlerName = `encrypt_${String(propertyName)}`\n const afterHandlerName = `decrypt_${String(propertyName)}`\n\n // BeforeInsert and BeforeUpdate logic\n BeforeInsert()(target, beforeHandlerName)\n // getMetadataArgsStorage().entityListeners.push({\n // target: target.constructor,\n // propertyName: beforeHandlerName,\n // type: 'before-insert'\n // })\n\n BeforeUpdate()(target, beforeHandlerName)\n // getMetadataArgsStorage().entityListeners.push({\n // target: target.constructor,\n // propertyName: beforeHandlerName,\n // type: 'before-update'\n // })\n\n AfterLoad()(target, afterHandlerName)\n // getMetadataArgsStorage().entityListeners.push({\n // target: target.constructor,\n // propertyName: afterHandlerName,\n // type: 'after-load'\n // })\n\n target[beforeHandlerName] = function (this) {\n // TODO 암호화 로직\n if (this[propertyName]) {\n // const salt = randomBytes(16).toString('hex')\n // const key = scryptSync(process.env.ENCRYPTION_KEY!, salt, 32)\n // const iv = randomBytes(16)\n // const cipher = createCipheriv(ALGORITHM, key, iv)\n // const encrypted = Buffer.concat([cipher.update(this[propertyName]), cipher.final()])\n // this[propertyName] = `${salt}.${iv.toString('hex')}.${encrypted.toString('hex')}`\n }\n }\n\n target[afterHandlerName] = function (this) {\n // TODO 복호화 로직\n if (this[propertyName]) {\n // const salt = randomBytes(16).toString('hex')\n // const key = scryptSync(process.env.ENCRYPTION_KEY!, salt, 32)\n // const iv = randomBytes(16)\n // const cipher = createCipheriv(ALGORITHM, key, iv)\n // const encrypted = Buffer.concat([cipher.update(this[propertyName]), cipher.final()])\n // this[propertyName] = `${salt}.${iv.toString('hex')}.${encrypted.toString('hex')}`\n }\n }\n }\n}\n\n// import { BeforeInsert, BeforeUpdate, Column, getMetadataArgsStorage } from 'typeorm'\n// import { randomBytes, createCipheriv, createDecipheriv, scryptSync } from 'crypto'\n// import { dataEncryptionKey } from './get-data-encryption-key'\n\n// const ALGORITHM = 'aes-256-gcm'\n\n// export function EncryptedColumn(): PropertyDecorator {\n// return function (target: Object, propertyName: string | symbol) {\n// Column(\"text\", { nullable: true })(target, propertyName);\n\n// const className = target.constructor.name;\n\n// BeforeInsert()(target, \"encryptField\");\n// BeforeUpdate()(target, \"encryptField\");\n\n// getMetadataArgsStorage().entityListeners.push({\n// target: className,\n// propertyName: \"encryptField\",\n// type: \"beforeInsert\"\n// });\n\n// getMetadataArgsStorage().entityListeners.push({\n// target: className,\n// propertyName: \"encryptField\",\n// type: \"beforeUpdate\"\n// });\n\n// target[\"encryptField\"] = function() {\n// const salt = randomBytes(16).toString('hex');\n// const key = scryptSync(dataEncryptionKey!, salt, 32);\n\n// const iv = randomBytes(16);\n// const cipher = createCipheriv(ALGORITHM, key, iv);\n// const encrypted = Buffer.concat([cipher.update(this[propertyName as string]), cipher.final()]);\n\n// this[propertyName as string] = `${salt}.${iv.toString('hex')}.${encrypted.toString('hex')}`;\n// }\n\n// // 원래의 프로퍼티 이름을 저장하는 변수를 선언\n// const originalPropertyName = `_${String(propertyName)}`\n\n// // 기본 컬럼 데코레이터\n// Column('text', { nullable: true })(target, originalPropertyName)\n\n// Object.defineProperty(target, propertyName, {\n// get: function () {\n// const [salt, ivHex, encryptedHex] = (this[originalPropertyName] || '').split('.')\n// const key = scryptSync(dataEncryptionKey!, salt, 32)\n\n// try {\n// const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(ivHex, 'hex'))\n// const decrypted = Buffer.concat([decipher.update(Buffer.from(encryptedHex, 'hex')), decipher.final()])\n\n// return decrypted.toString()\n// } catch (err) {\n// console.error(`decryption for ${String(propertyName)} field failed`)\n// return null\n// }\n// },\n// set: function (value) {\n// const salt = randomBytes(16).toString('hex')\n// const key = scryptSync(dataEncryptionKey!, salt, 32)\n\n// const iv = randomBytes(16)\n// const cipher = createCipheriv(ALGORITHM, key, iv)\n// const encrypted = Buffer.concat([cipher.update(value), cipher.final()])\n\n// this[originalPropertyName] = `${salt}.${iv.toString('hex')}.${encrypted.toString('hex')}`\n// }\n// })\n// }\n// }\n"]}
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const dataEncryptionKey: any;
|
@@ -0,0 +1,15 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.dataEncryptionKey = void 0;
|
4
|
+
const env_1 = require("@things-factory/env");
|
5
|
+
var _DATA_ENCRYPTION_KEY = env_1.config.get('dataEncryptionKey');
|
6
|
+
if (!_DATA_ENCRYPTION_KEY) {
|
7
|
+
if (process.env.NODE_ENV == 'production') {
|
8
|
+
throw new TypeError('dataEncryptionKey not configured.');
|
9
|
+
}
|
10
|
+
else {
|
11
|
+
_DATA_ENCRYPTION_KEY = 'V6g5oHJZb7KcYzIyL6cM95XvIDouon5b';
|
12
|
+
}
|
13
|
+
}
|
14
|
+
exports.dataEncryptionKey = _DATA_ENCRYPTION_KEY;
|
15
|
+
//# sourceMappingURL=get-data-encryption-key.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"get-data-encryption-key.js","sourceRoot":"","sources":["../../server/typeorm/get-data-encryption-key.ts"],"names":[],"mappings":";;;AAAA,6CAA4C;AAE5C,IAAI,oBAAoB,GAAG,YAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAA;AAE1D,IAAI,CAAC,oBAAoB,EAAE;IACzB,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,YAAY,EAAE;QACxC,MAAM,IAAI,SAAS,CAAC,mCAAmC,CAAC,CAAA;KACzD;SAAM;QACL,oBAAoB,GAAG,kCAAkC,CAAA;KAC1D;CACF;AAEY,QAAA,iBAAiB,GAAG,oBAAoB,CAAA","sourcesContent":["import { config } from '@things-factory/env'\n\nvar _DATA_ENCRYPTION_KEY = config.get('dataEncryptionKey')\n\nif (!_DATA_ENCRYPTION_KEY) {\n if (process.env.NODE_ENV == 'production') {\n throw new TypeError('dataEncryptionKey not configured.')\n } else {\n _DATA_ENCRYPTION_KEY = 'V6g5oHJZb7KcYzIyL6cM95XvIDouon5b'\n }\n}\n\nexport const dataEncryptionKey = _DATA_ENCRYPTION_KEY\n"]}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@things-factory/shell",
|
3
|
-
"version": "6.1.
|
3
|
+
"version": "6.1.189",
|
4
4
|
"description": "Core module for framework",
|
5
5
|
"bin": {
|
6
6
|
"things-factory": "bin/things-factory",
|
@@ -62,7 +62,7 @@
|
|
62
62
|
"@things-factory/ejs-remote": "^6.1.175",
|
63
63
|
"@things-factory/env": "^6.1.175",
|
64
64
|
"@things-factory/styles": "^6.1.175",
|
65
|
-
"@things-factory/utils": "^6.1.
|
65
|
+
"@things-factory/utils": "^6.1.186",
|
66
66
|
"@webcomponents/webcomponentsjs": "^2.6.0",
|
67
67
|
"args": "^5.0.0",
|
68
68
|
"broadcastchannel-polyfill": "^1.0.1",
|
@@ -132,5 +132,5 @@
|
|
132
132
|
"pg": "^8.7.3",
|
133
133
|
"sqlite3": "^5.0.8"
|
134
134
|
},
|
135
|
-
"gitHead": "
|
135
|
+
"gitHead": "0a7d81fcf229582aa643223c56ece75a0432f7d8"
|
136
136
|
}
|
package/server/index.ts
CHANGED
@@ -0,0 +1,44 @@
|
|
1
|
+
import { ValueTransformer } from 'typeorm'
|
2
|
+
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'crypto'
|
3
|
+
|
4
|
+
import { dataEncryptionKey } from './get-data-encryption-key'
|
5
|
+
|
6
|
+
const ALGORITHM = 'aes-256-cbc'
|
7
|
+
const KEY_LENGTH = 32
|
8
|
+
const SALT_LENGTH = 16
|
9
|
+
const IV_LENGTH = 16
|
10
|
+
|
11
|
+
export const encryptTransformer: ValueTransformer = {
|
12
|
+
to: (entityValue: string) => encrypt(entityValue), // DB에 저장하기 전에 암호화
|
13
|
+
from: (databaseValue: string) => decrypt(databaseValue) // DB에서 값을 가져올 때 복호화
|
14
|
+
}
|
15
|
+
|
16
|
+
function encrypt(text: string): string {
|
17
|
+
if (!text) {
|
18
|
+
return null
|
19
|
+
}
|
20
|
+
|
21
|
+
const iv = randomBytes(IV_LENGTH)
|
22
|
+
const cipher = createCipheriv(ALGORITHM, dataEncryptionKey, iv)
|
23
|
+
const encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()])
|
24
|
+
|
25
|
+
return `${iv.toString('hex')}:${encrypted.toString('hex')}`
|
26
|
+
}
|
27
|
+
|
28
|
+
function decrypt(text: string): string {
|
29
|
+
if (!text) {
|
30
|
+
return null
|
31
|
+
}
|
32
|
+
|
33
|
+
try {
|
34
|
+
const parts = text.split(':')
|
35
|
+
const iv = Buffer.from(parts.shift(), 'hex')
|
36
|
+
const encryptedText = Buffer.from(parts.join(':'), 'hex')
|
37
|
+
const decipher = createDecipheriv(ALGORITHM, dataEncryptionKey, iv)
|
38
|
+
|
39
|
+
return Buffer.concat([decipher.update(encryptedText), decipher.final()]).toString('utf8')
|
40
|
+
} catch (err) {
|
41
|
+
console.error(`decryption for encrypted field failed in encryptTransformer`)
|
42
|
+
return null
|
43
|
+
}
|
44
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { config } from '@things-factory/env'
|
2
|
+
|
3
|
+
var _DATA_ENCRYPTION_KEY = config.get('dataEncryptionKey')
|
4
|
+
|
5
|
+
if (!_DATA_ENCRYPTION_KEY) {
|
6
|
+
if (process.env.NODE_ENV == 'production') {
|
7
|
+
throw new TypeError('dataEncryptionKey not configured.')
|
8
|
+
} else {
|
9
|
+
_DATA_ENCRYPTION_KEY = 'V6g5oHJZb7KcYzIyL6cM95XvIDouon5b'
|
10
|
+
}
|
11
|
+
}
|
12
|
+
|
13
|
+
export const dataEncryptionKey = _DATA_ENCRYPTION_KEY
|