DB (encrypted) export/import
This commit is contained in:
parent
223c47133b
commit
bfd630ec26
2 changed files with 133 additions and 32 deletions
|
@ -5,6 +5,8 @@ import CommunicationTypeService from "../../service/communicationTypeService";
|
||||||
import ExecutivePositionService from "../../service/executivePositionService";
|
import ExecutivePositionService from "../../service/executivePositionService";
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import { type BinaryLike } from "node:crypto";
|
import { type BinaryLike } from "node:crypto";
|
||||||
|
import { CreateAwardCommand } from "../../command/awardCommand";
|
||||||
|
import AwardCommandHandler from "../../command/awardCommandHandler";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description get all data stored in the database as a single json object
|
* @description get all data stored in the database as a single json object
|
||||||
|
@ -13,12 +15,40 @@ import { type BinaryLike } from "node:crypto";
|
||||||
* @returns {Promise<*>}
|
* @returns {Promise<*>}
|
||||||
*/
|
*/
|
||||||
export async function getDatabaseExport(req: Request, res: Response): Promise<any> {
|
export async function getDatabaseExport(req: Request, res: Response): Promise<any> {
|
||||||
const { secret } = req.body;
|
const noEncryption = req.headers["x-encrypt-no"];
|
||||||
|
|
||||||
|
const secret = req.headers["x-encrypt-with"];
|
||||||
try {
|
try {
|
||||||
if (!secret) {
|
if (!secret && !noEncryption) {
|
||||||
res.status(400).send('Empty encryption key');
|
res.status(400).send("Empty encryption key");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let data: any = {};
|
||||||
|
|
||||||
|
console.log("Exporting awards...");
|
||||||
|
data.awards = await AwardService.getAll();
|
||||||
|
console.log(`Exported ${data.awards.length} awards`);
|
||||||
|
console.log("Exporting communication types...");
|
||||||
|
data.communicationTypes = await CommunicationTypeService.getAll();
|
||||||
|
console.log(`Exported ${data.communicationTypes.length} communicationTypes`);
|
||||||
|
console.log("Exporting executivePositions...");
|
||||||
|
data.executivePositions = await ExecutivePositionService.getAll();
|
||||||
|
console.log(`Exported ${data.executivePositions.length} executivePositions`);
|
||||||
|
console.log("Exporting members...");
|
||||||
|
data.members = await MemberService.getAll();
|
||||||
|
console.log(`Exported ${data.members.length} members`);
|
||||||
|
|
||||||
|
if (noEncryption) {
|
||||||
|
console.log(`Sending data unencrypted with length ${data.length}`);
|
||||||
|
res.json({
|
||||||
|
encrypted: !noEncryption,
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
console.log("finished encrypted data");
|
||||||
|
} else {
|
||||||
|
const dataStr: string = JSON.stringify(data);
|
||||||
|
console.log(`Encrypting data...`);
|
||||||
const iv = await new Promise((resolve, reject) => {
|
const iv = await new Promise((resolve, reject) => {
|
||||||
// create initialization vector
|
// create initialization vector
|
||||||
crypto.randomBytes(16, (err, iv) => {
|
crypto.randomBytes(16, (err, iv) => {
|
||||||
|
@ -29,36 +59,103 @@ export async function getDatabaseExport(req: Request, res: Response): Promise<an
|
||||||
resolve(iv);
|
resolve(iv);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let data: any = {};
|
|
||||||
|
|
||||||
console.log('Exporting awards...');
|
|
||||||
data.awards = await AwardService.getAll();
|
|
||||||
console.log(`Exported ${data.awards.length} awards`);
|
|
||||||
console.log('Exporting communication types...');
|
|
||||||
data.communicationTypes = await CommunicationTypeService.getAll();
|
|
||||||
console.log(`Exported ${data.communicationTypes.length} communicationTypes`);
|
|
||||||
console.log('Exporting executivePositions...');
|
|
||||||
data.executivePositions = await ExecutivePositionService.getAll();
|
|
||||||
console.log(`Exported ${data.executivePositions.length} executivePositions`);
|
|
||||||
console.log('Exporting members...');
|
|
||||||
data.members = await MemberService.getAll();
|
|
||||||
console.log(`Exported ${data.members.length} members`);
|
|
||||||
|
|
||||||
console.log(`Encrypting data...`);
|
|
||||||
// encrypt data
|
// encrypt data
|
||||||
const dataStr: string = JSON.stringify(data);
|
let base64Key = crypto.createHash("sha256").update(String(secret)).digest("base64");
|
||||||
let base64Key = crypto.createHash('sha256').update(String(secret)).digest('base64');
|
const key = Buffer.from(base64Key, "base64");
|
||||||
const key = Buffer.from(base64Key, 'base64')
|
|
||||||
let cipher = crypto.createCipheriv("aes-256-gcm", key, iv as BinaryLike);
|
|
||||||
const encryptedData: string = cipher.update(dataStr, 'utf8', 'hex') + cipher.final('hex');
|
|
||||||
|
|
||||||
res.json({
|
// create initialization vector
|
||||||
data: encryptedData,
|
const randomIV: Buffer = await new Promise((resolve, reject) => {
|
||||||
});
|
crypto.randomBytes(16, (err, iv) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
catch(ex) {
|
resolve(iv);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// console.log(`iv: ${randomIV.toString('hex')}`);
|
||||||
|
// console.log(`key: ${key.toString('hex')}`);
|
||||||
|
|
||||||
|
let cipher = crypto.createCipheriv("aes-256-gcm", key, randomIV);
|
||||||
|
const encryptedData: string = cipher.update(dataStr, "utf8", "hex") + cipher.final("hex");
|
||||||
|
const authTag = cipher.getAuthTag().toString("hex");
|
||||||
|
|
||||||
|
// console.log(`authTag: ${authTag}`);
|
||||||
|
console.log(`Sending encrypted data with length ${encryptedData.length}`);
|
||||||
|
res.json({
|
||||||
|
encrypted: !noEncryption,
|
||||||
|
iv: randomIV.toString("base64"),
|
||||||
|
data: encryptedData,
|
||||||
|
authTag: authTag,
|
||||||
|
});
|
||||||
|
console.log("finished encrypted data");
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
console.log(ex);
|
console.log(ex);
|
||||||
res.status(500).send(ex.message ? ex.message : 'Exception!');
|
res.status(500).send(ex.message ? ex.message : "Exception!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description decrypt the import data and use it to re-fill the database
|
||||||
|
* @param req {Request} Express req object
|
||||||
|
* @param res {Response} Express res object
|
||||||
|
* @returns {Promise<*>}
|
||||||
|
*/
|
||||||
|
export async function importDatabaseExport(req: Request, res: Response): Promise<any> {
|
||||||
|
const { data: receivedData } = req.body;
|
||||||
|
if (!receivedData) {
|
||||||
|
res.status(400).send("Empty database import data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const noEncryption = req.headers["x-encrypt-no"];
|
||||||
|
try {
|
||||||
|
let data;
|
||||||
|
if (noEncryption) {
|
||||||
|
data = receivedData;
|
||||||
|
} else {
|
||||||
|
const secret = req.headers["x-decrypt-with"];
|
||||||
|
const { iv, authTag } = req.body;
|
||||||
|
if (!secret) {
|
||||||
|
res.status(400).send("Empty decryption key");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!iv) {
|
||||||
|
res.status(400).send("Empty database import iv");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!authTag) {
|
||||||
|
res.status(400).send("Empty database import authTag");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare the secret to be in a buffer
|
||||||
|
const base64Key = crypto.createHash("sha256").update(String(secret)).digest("base64");
|
||||||
|
const key = Buffer.from(base64Key, "base64");
|
||||||
|
|
||||||
|
// decrypt data
|
||||||
|
const ivString = Buffer.from(iv, "base64");
|
||||||
|
// console.log(`iv: ${ivString.toString('hex')}`);
|
||||||
|
// console.log(`key: ${key.toString('hex')}`);
|
||||||
|
// console.log(`authTag: ${authTag}`);
|
||||||
|
const decipher = crypto.createDecipheriv("aes-256-gcm", key, ivString);
|
||||||
|
decipher.setAuthTag(Buffer.from(authTag, "hex"));
|
||||||
|
const decrypted = decipher.update(receivedData, "hex", "utf-8") + decipher.final("utf-8");
|
||||||
|
data = JSON.parse(decrypted.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const award of data.awards) {
|
||||||
|
let createAward: CreateAwardCommand = {
|
||||||
|
award: award,
|
||||||
|
};
|
||||||
|
const awardId: any = await AwardCommandHandler.create(createAward);
|
||||||
|
console.log(`Award with id ${awardId} created`);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.send(200);
|
||||||
|
} catch (ex) {
|
||||||
|
console.log(ex);
|
||||||
|
res.status(500).send(ex.message ? ex.message : "Exception!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
import express, { Request, Response } from "express";
|
import express, { Request, Response } from "express";
|
||||||
import { getDatabaseExport } from "../../controller/admin/exportController";
|
import { getDatabaseExport, importDatabaseExport } from "../../controller/admin/exportController";
|
||||||
|
|
||||||
const router = express.Router({ mergeParams: true });
|
const router = express.Router({ mergeParams: true });
|
||||||
|
|
||||||
router.post("/", async (req: Request, res: Response) => {
|
router.get("/", async (req: Request, res: Response) => {
|
||||||
await getDatabaseExport(req, res);
|
await getDatabaseExport(req, res);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.post("/", async (req: Request, res: Response) => {
|
||||||
|
await importDatabaseExport(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
Loading…
Reference in a new issue