-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmongoose-aes-encryption.js
More file actions
84 lines (75 loc) · 2.99 KB
/
mongoose-aes-encryption.js
File metadata and controls
84 lines (75 loc) · 2.99 KB
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
const { parseKey, encrypt, decrypt } = require('./lib/crypto');
const allowedAlgorithms = ['aes-256-gcm', 'aes-256-cbc'];
function makeGetterSetter(originalType, parsedKey, algorithm, isArray) {
function toString(v) {
if (originalType === Date) {
return new Date(v).toISOString();
}
return String(v);
}
function fromString(v) {
if (originalType === Number) {
return parseFloat(v);
}
if (originalType === Date) {
return new Date(v);
}
if (originalType === Boolean) {
return v === 'true';
}
return v;
}
return {
get(v) {
if (v === null || v === undefined) return v;
if (isArray && Array.isArray(v)) {
return v.map(elem => elem == null ? elem : fromString(decrypt(elem, { key: parsedKey, passNull: true })));
}
const decrypted = decrypt(v, { key: parsedKey, passNull: true });
return fromString(decrypted);
},
set(v) {
if (v === null || v === undefined) return v;
if (isArray && Array.isArray(v)) {
return v.map(elem => elem == null ? elem : encrypt(toString(elem), { key: parsedKey, passNull: true, algorithm }));
}
return encrypt(toString(v), { key: parsedKey, passNull: true, algorithm });
}
};
}
module.exports = function createAESPlugin(options) {
if (!options || !options.key) {
throw new Error('mongoose-aes-encryption: options.key is required');
}
const algorithm = options.algorithm ?? 'aes-256-gcm';
if (!allowedAlgorithms.includes(algorithm)) {
throw new Error(`mongoose-aes-encryption: invalid algorithm '${algorithm}'. Allowed: ${allowedAlgorithms.join(', ')}`);
}
const key = options.key;
const parsedKey = parseKey(key);
return function encryptedPlugin(schema) {
const pathsToRewrite = [];
schema.eachPath((pathname, schemaType) => {
if (schemaType.options && schemaType.options.encrypted === true) {
const rawType = schemaType.options.type;
if (Array.isArray(rawType) && rawType.length === 1) {
pathsToRewrite.push({ pathname, originalType: rawType[0], isArray: true });
} else {
pathsToRewrite.push({ pathname, originalType: rawType, isArray: false });
}
}
});
for (const { pathname, originalType, isArray } of pathsToRewrite) {
const { get, set } = makeGetterSetter(originalType, parsedKey, algorithm, isArray);
const existingOptions = schema.path(pathname).options;
const newOptions = Object.assign({}, existingOptions, {
type: schema.constructor.Types.Mixed,
get,
set
});
schema.path(pathname, newOptions);
}
};
};
module.exports.encrypt = encrypt;
module.exports.decrypt = decrypt;