-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathindex.js
94 lines (74 loc) · 2.97 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
var crypto = require('crypto');
function EncryptedField(Sequelize, key, opt) {
if (!(this instanceof EncryptedField)) {
return new EncryptedField(Sequelize, key, opt);
}
var self = this;
self.key = new Buffer(key, 'hex');
self.Sequelize = Sequelize;
opt = opt || {};
self._algorithm = opt.algorithm || 'aes-256-cbc';
self._iv_length = opt.iv_length || 16;
self.encrypted_field_name = undefined;
};
EncryptedField.prototype.vault = function(name) {
var self = this;
if (self.encrypted_field_name) {
throw new Error('vault already initialized');
}
self.encrypted_field_name = name;
return {
type: self.Sequelize.BLOB,
get: function() {
var previous = this.getDataValue(name);
if (!previous) {
return {};
}
previous = new Buffer(previous);
var iv = previous.slice(0, self._iv_length);
var content = previous.slice(self._iv_length, previous.length);
var decipher = crypto.createDecipheriv(self._algorithm, self.key, iv);
var json = decipher.update(content, undefined, 'utf8') + decipher.final('utf8');
return JSON.parse(json);
},
set: function(value) {
// if new data is set, we will use a new IV
var new_iv = crypto.randomBytes(self._iv_length);
var cipher = crypto.createCipheriv(self._algorithm, self.key, new_iv);
cipher.end(JSON.stringify(value), 'utf-8');
var enc_final = Buffer.concat([new_iv, cipher.read()]);
var previous = this.setDataValue(name, enc_final);
}
}
};
EncryptedField.prototype.field = function(name, config) {
var self = this;
config = config || {};
config.validate = config.validate || {};
var hasValidations = [undefined,null].indexOf(typeof config.validate) === -1;
if (!self.encrypted_field_name) {
throw new Error('you must initialize the vault field before using encrypted fields');
}
var encrypted_field_name = self.encrypted_field_name;
return {
type: self.Sequelize.VIRTUAL(config.type || null),
set: function set_encrypted(val) {
if (hasValidations) {
this.setDataValue(name, val);
}
// use `this` not self because we need to reference the sequelize instance
// not our EncryptedField instance
var encrypted = this[encrypted_field_name];
encrypted[name] = val;
this[encrypted_field_name] = encrypted;
},
get: function get_encrypted() {
var encrypted = this[encrypted_field_name];
var val = encrypted[name];
return ([undefined, null].indexOf(val) === -1) ? val : config.defaultValue;
},
allowNull: ([undefined, null].indexOf(config.allowNull) === -1) ? config.allowNull : true,
validate: config.validate
}
};
module.exports = EncryptedField;