Compare commits
4 commits
main
...
anton/expo
Author | SHA1 | Date | |
---|---|---|---|
bfd630ec26 | |||
223c47133b | |||
|
36d47b0d12 | ||
5503749705 |
6 changed files with 192 additions and 7 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -130,3 +130,5 @@ dist
|
|||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
# WebStorm
|
||||
.idea/
|
||||
|
|
161
src/controller/admin/exportController.ts
Normal file
161
src/controller/admin/exportController.ts
Normal file
|
@ -0,0 +1,161 @@
|
|||
import { Request, Response } from "express";
|
||||
import MemberService from "../../service/memberService";
|
||||
import AwardService from "../../service/awardService";
|
||||
import CommunicationTypeService from "../../service/communicationTypeService";
|
||||
import ExecutivePositionService from "../../service/executivePositionService";
|
||||
import crypto from "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
|
||||
* @param req {Request} Express req object
|
||||
* @param res {Response} Express res object
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
export async function getDatabaseExport(req: Request, res: Response): Promise<any> {
|
||||
const noEncryption = req.headers["x-encrypt-no"];
|
||||
|
||||
const secret = req.headers["x-encrypt-with"];
|
||||
try {
|
||||
if (!secret && !noEncryption) {
|
||||
res.status(400).send("Empty encryption key");
|
||||
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) => {
|
||||
// create initialization vector
|
||||
crypto.randomBytes(16, (err, iv) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve(iv);
|
||||
});
|
||||
});
|
||||
// encrypt data
|
||||
let base64Key = crypto.createHash("sha256").update(String(secret)).digest("base64");
|
||||
const key = Buffer.from(base64Key, "base64");
|
||||
|
||||
// create initialization vector
|
||||
const randomIV: Buffer = await new Promise((resolve, reject) => {
|
||||
crypto.randomBytes(16, (err, iv) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
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);
|
||||
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!");
|
||||
}
|
||||
}
|
|
@ -23,11 +23,12 @@ export const CLUB_NAME = process.env.CLUB_NAME ?? "";
|
|||
|
||||
export function configCheck() {
|
||||
if (DB_TYPE != "mysql" && DB_TYPE != "sqlite") throw new Error("set valid value to DB_TYPE (mysql|sqlite)");
|
||||
if (DB_TYPE !== 'sqlite') {
|
||||
if (DB_HOST == "" ?? typeof DB_HOST != "string") throw new Error("set valid value to DB_HOST");
|
||||
if (DB_NAME == "" ?? typeof DB_NAME != "string") throw new Error("set valid value to DB_NAME");
|
||||
if (DB_USERNAME == "" ?? typeof DB_USERNAME != "string") throw new Error("set valid value to DB_USERNAME");
|
||||
if (DB_PASSWORD == "" ?? typeof DB_PASSWORD != "string") throw new Error("set valid value to DB_PASSWORD");
|
||||
|
||||
}
|
||||
if (typeof SERVER_PORT != "number") throw new Error("set valid numeric value to SERVER_PORT");
|
||||
|
||||
if (JWT_SECRET == "" ?? typeof JWT_SECRET != "string") throw new Error("set valid value to JWT_SECRET");
|
||||
|
|
15
src/routes/admin/database.ts
Normal file
15
src/routes/admin/database.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import express, { Request, Response } from "express";
|
||||
import { getDatabaseExport, importDatabaseExport } from "../../controller/admin/exportController";
|
||||
|
||||
const router = express.Router({ mergeParams: true });
|
||||
|
||||
router.get("/", async (req: Request, res: Response) => {
|
||||
await getDatabaseExport(req, res);
|
||||
});
|
||||
|
||||
router.post("/", async (req: Request, res: Response) => {
|
||||
await importDatabaseExport(req, res);
|
||||
});
|
||||
|
||||
|
||||
export default router;
|
|
@ -12,6 +12,8 @@ import member from "./member";
|
|||
import role from "./role";
|
||||
import user from "./user";
|
||||
|
||||
import database from "./database";
|
||||
|
||||
var router = express.Router({ mergeParams: true });
|
||||
|
||||
router.use("/award", PermissionHelper.passCheckMiddleware("read", "settings", "award"), award);
|
||||
|
@ -37,4 +39,6 @@ router.use("/member", PermissionHelper.passCheckMiddleware("read", "club", "memb
|
|||
router.use("/role", PermissionHelper.passCheckMiddleware("read", "user", "role"), role);
|
||||
router.use("/user", PermissionHelper.passCheckMiddleware("read", "user", "user"), user);
|
||||
|
||||
router.use("/database", PermissionHelper.passCheckMiddleware("read", "settings", "database"), database);
|
||||
|
||||
export default router;
|
||||
|
|
|
@ -11,7 +11,8 @@ export type PermissionModule =
|
|||
| "communication"
|
||||
| "membership_status"
|
||||
| "user"
|
||||
| "role";
|
||||
| "role"
|
||||
| "database";
|
||||
|
||||
export type PermissionType = "read" | "create" | "update" | "delete";
|
||||
|
||||
|
@ -47,10 +48,11 @@ export const permissionModules: Array<PermissionModule> = [
|
|||
"membership_status",
|
||||
"user",
|
||||
"role",
|
||||
"database",
|
||||
];
|
||||
export const permissionTypes: Array<PermissionType> = ["read", "create", "update", "delete"];
|
||||
export const sectionsAndModules: SectionsAndModulesObject = {
|
||||
club: ["member", "calendar", "newsletter", "protocoll"],
|
||||
settings: ["qualification", "award", "executive_position", "communication", "membership_status"],
|
||||
settings: ["qualification", "award", "executive_position", "communication", "membership_status", "database"],
|
||||
user: ["user", "role"],
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue