@oversightstudio/encrypted-fields
Version:
Database field encryption for Payload.
134 lines (123 loc) • 4.24 kB
JavaScript
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
// src/fields/encryptedField.ts
import * as validationFunctions from "payload/shared";
// src/utils/toPascalCase.ts
function toPascalCase(name) {
return name.charAt(0).toUpperCase() + name.slice(1);
}
// src/utils/decrypt.ts
import crypto2 from "crypto";
// src/utils/encrypt.ts
import crypto from "crypto";
// src/consts.ts
var algorithm = "aes-256-ctr";
// src/utils/encrypt.ts
var createKeyFromSecret = (secretKey) => crypto.createHash("sha256").update(secretKey).digest("hex").slice(0, 32);
var encrypt = (text) => {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(
algorithm,
createKeyFromSecret(process.env.PAYLOAD_SECRET),
iv
);
const encrypted = Buffer.concat([cipher.update(text), cipher.final()]);
return `${iv.toString("hex")}${encrypted.toString("hex")}`;
};
// src/utils/decrypt.ts
var decrypt = (hash) => {
const iv = hash.slice(0, 32);
const content = hash.slice(32);
const decipher = crypto2.createDecipheriv(
algorithm,
createKeyFromSecret(process.env.PAYLOAD_SECRET),
Buffer.from(iv, "hex")
);
const decrypted = Buffer.concat([decipher.update(Buffer.from(content, "hex")), decipher.final()]);
return decrypted.toString();
};
// src/hooks/decryptField.ts
var decryptField = (value) => {
if (value === void 0 || value === null) return void 0;
try {
return JSON.parse(decrypt(value));
} catch (e) {
return void 0;
}
};
// src/hooks/encryptField.ts
var encryptField = (value) => {
if (value === void 0 || value === null) return void 0;
return encrypt(JSON.stringify(value));
};
// src/fields/encryptedField.ts
var encryptedField = (data) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
let fieldComponentName = toPascalCase(data.type);
switch (data.type) {
case "date":
fieldComponentName = "DateTime";
break;
case "json":
fieldComponentName = "JSON";
break;
case "radio":
fieldComponentName = "RadioGroup";
default:
break;
}
return __spreadProps(__spreadValues({}, data), {
type: "text",
validate: (encryptedValue, args) => {
const value = decryptField(encryptedValue);
return validationFunctions[data.type](value, args);
},
hooks: __spreadProps(__spreadValues({}, data.hooks), {
beforeChange: [
...(_b = (_a = data.hooks) == null ? void 0 : _a.beforeChange) != null ? _b : [],
({ value }) => {
if ("hasMany" in data && data.hasMany && Array.isArray(value)) {
return value.map((item) => encryptField(item));
}
return encryptField(value);
}
],
afterRead: [
...(_d = (_c = data.hooks) == null ? void 0 : _c.afterRead) != null ? _d : [],
({ value }) => {
if (Array.isArray(value)) {
return value.map((item) => decryptField(item));
}
return decryptField(value);
}
]
}),
admin: __spreadProps(__spreadValues({}, data.admin), {
components: __spreadProps(__spreadValues({}, (_f = (_e = data.admin) == null ? void 0 : _e.components) != null ? _f : {}), {
Field: __spreadValues({
path: `@payloadcms/ui#${fieldComponentName}Field`
}, (_i = (_h = (_g = data.admin) == null ? void 0 : _g.components) == null ? void 0 : _h.Field) != null ? _i : {})
})
})
});
};
export {
encryptedField
};