UNPKG

limelightdb

Version:
315 lines (314 loc) 15.2 kB
"use strict"; exports.__esModule = true; exports.Table = exports.Database = exports.LimelightDB = void 0; var ajv_1 = require("ajv"); var crypto = require("crypto"); var fs = require("fs"); var path = require("path"); var server_1 = require("./server"); var LimelightDB = /** @class */ (function () { function LimelightDB(filename, humanReadable, key, port) { if (key === void 0) { key = null; } var _this = this; this.initialize = function () { if (!fs.existsSync(_this.filename) || fs.statSync(_this.filename).size == 0) _this.write(new Database()); else { var database = void 0; try { database = JSON.parse(fs.readFileSync(_this.filename, "utf-8")); } catch (e) { throw new Error("Database is corrupted."); } if (!database.iv && !database.encryptedData && _this.key) { console.log("Database is not encrypted, but a key is provided. Rebuilding..."); _this.write(new Database(database)); console.log("Database is now encrypted! If this was accidental, you can remove the key with the \".decrypt()\" method."); } else if (database.iv && database.encryptedData && !_this.key) throw new Error("Database is encrypted, but no key is provided."); else if (database.iv && database.encryptedData && _this.key) { try { _this.read(); } catch (e) { throw new Error("Database is encrypted, and the key provided is invalid, or the database is corrupted."); } } else { try { _this.read(); } catch (e) { throw new Error("Database is corrupted."); } } if ((database.iv && database.encryptedData) || (!database.iv && !database.encryptedData && _this.key)) _this.encrypted = true; } if (_this.port && _this.key) { _this.server = (0, server_1.startServer)(_this); } _this.version = "3.1.5"; return _this; }; this.stopServer = function () { if (_this.server) _this.server.close(); }; this.decrypt = function (key) { var database = JSON.parse(fs.readFileSync(_this.filename, "utf-8")); if (!database.iv && !database.encryptedData) throw new Error("Database is not encrypted."); console.log("Decrypting database with key..."); if (_this.key) _this.write(new Database(JSON.parse(decrypt(database, _this.key))), true); else if (key) _this.write(new Database(JSON.parse(decrypt(database, key))), true); else throw new Error("No key is provided."); console.log("Database is now decrypted. Do not provide a key when initializing the database or it will be re-encrypted."); _this.key = null; _this.encrypted = false; return _this; }; this.alter = function (table, changes) { var database = _this.read(); var selectedTable = database.tables.find(function (x) { return x.name == table; }); if (!selectedTable) throw new Error("Table \"".concat(table, "\" does not exist. Did you mean to create it (\".create(...)\" method)?")); selectedTable.alterTable(changes, database); _this.write(database); }; this.select = function (table, filter, limit) { var database = _this.read(); var selectedTable = database.tables.find(function (x) { return x.name == table; }); if (!selectedTable) throw new Error("Table \"".concat(table, "\" does not exist. Did you mean to create it (\".create(...)\" method)?")); if (!selectedTable.rows) return []; if (!limit) return selectedTable.rows.filter(function (x) { return filter(x); }); else return selectedTable.rows.filter(function (x) { return filter(x); }).slice(0, limit); }; this.create = function (table, cols, schema, autoID) { var database = _this.read(); if (!database.tables) database.tables = []; var selectedTable = database.tables.find(function (x) { return x.name == table; }); if (selectedTable) throw new Error("Table \"".concat(table, "\" already exists.")); if (cols.length != Object.keys(schema).length) throw new Error("Schema does not match columns."); cols.forEach(function (x) { if (Object.keys(schema).indexOf(x) == -1) throw new Error("Schema does not match columns."); }); if (!schema["id"]) schema["id"] = { type: "number" }; database.tables.push(new Table(table, cols, { type: "object", properties: schema, required: cols, additionalProperties: false }, autoID)); _this.write(database); }; this.insert = function (table, rows) { var database = _this.read(); var selectedTable = database.tables.find(function (x) { return x.name == table; }); if (!selectedTable) throw new Error("Table \"".concat(table, "\" does not exist. Did you mean to create it (\".create(...)\" method)?")); rows.forEach(function (x) { return selectedTable.createRow(x); }); _this.write(database); }; this.update = function (table, filter, row) { var database = _this.read(); var selectedTable = database.tables.find(function (x) { return x.name == table; }); if (!selectedTable) throw new Error("Table \"".concat(table, "\" does not exist. Did you mean to create it (\".create(...)\" method)?")); var rows = selectedTable.rows.filter(function (x) { return filter(x); }); if (!(rows === null || rows === void 0 ? void 0 : rows.length)) return; var _loop_1 = function () { var newRow = Object.assign({}, rows[i], row); var tempId = void 0; if (newRow["id"] && selectedTable.autoId) { tempId = newRow["id"]; delete newRow["id"]; } Object.keys(newRow).forEach(function (x) { if (selectedTable.schema.properties[x].type == "number") newRow[x] = parseInt(newRow[x]); }); Object.keys(row).forEach(function (x) { if (selectedTable.schema.properties[x].type == "number") row[x] = parseInt(row[x]); }); if (!new ajv_1["default"]().compile(selectedTable.schema)(newRow)) throw new Error("Error while updating row in \"".concat(table, "\"\n ").concat(JSON.stringify(newRow), " does not match\n ").concat(JSON.stringify(selectedTable.schema.properties), ".")); if (tempId && selectedTable.autoId) newRow["id"] = tempId; Object.assign(rows[i], row); }; for (var i = 0; i < rows.length; i++) { _loop_1(); } _this.write(database); }; this["delete"] = function (table, filter) { var database = _this.read(); var selectedTable = database.tables.find(function (x) { return x.name == table; }); if (!selectedTable) throw new Error("Table \"".concat(table, "\" does not exist. Did you mean to create it (\".create(...)\" method)?")); var rows = selectedTable.rows.filter(function (x) { return filter(x); }); if (!(rows === null || rows === void 0 ? void 0 : rows.length)) return; for (var i = 0; i < rows.length; i++) { var index = selectedTable.rows.indexOf(rows[i]); if (index == undefined) return; selectedTable.rows.splice(index, 1); } _this.write(database); }; this.read = function () { if (!_this.key) { return new Database(JSON.parse(fs.readFileSync(_this.filename, "utf-8"))); } else { return new Database(JSON.parse(decrypt(JSON.parse(fs.readFileSync(_this.filename, "utf-8")), _this.key))); } }; this.write = function (database, encryptOverride) { if (!_this.key || encryptOverride) { fs.writeFileSync(_this.filename, database.raw(_this.humanReadable)); } else { fs.writeFileSync(_this.filename, JSON.stringify(encrypt(database.raw(_this.humanReadable), _this.key), null, _this.humanReadable ? 2 : 0)); } }; this.filename = filename; if (!path.extname(filename)) this.filename += ".limelight"; this.humanReadable = humanReadable ? true : false; this.key = key; if (port) this.port = port; } return LimelightDB; }()); exports.LimelightDB = LimelightDB; var Database = /** @class */ (function () { function Database(database) { var _this = this; this.raw = function (humanReadable) { return JSON.stringify(_this, null, humanReadable ? 2 : 0); }; if (database === null || database === void 0 ? void 0 : database.tables) { this.tables = []; database.tables.forEach(function (x) { _this.tables.push(new Table(x.name, x.cols, x.schema, x.autoId, x.rows)); }); } } return Database; }()); exports.Database = Database; var Table = /** @class */ (function () { function Table(name, cols, schema, autoId, rows) { var _this = this; this.alterTable = function (changes, database) { var _a, _b; if (changes.schema) { Object.keys(changes.schema).forEach(function (x) { var _a; if (!_this.schema.properties[x] || _this.schema.properties[x].type != changes.schema[x].type) { (_a = _this.rows) === null || _a === void 0 ? void 0 : _a.forEach(function (y) { switch (changes.schema[x].type) { case "number": case "integer": y[x] = 0; break; case "string": y[x] = ""; break; case "boolean": y[x] = false; break; case "array": y[x] = []; break; case "object": y[x] = {}; break; case "null": y[x] = null; break; } }); } }); Object.keys(_this.schema.properties).forEach(function (x) { var _a; if (!changes.schema[x] && x != "id") (_a = _this.rows) === null || _a === void 0 ? void 0 : _a.forEach(function (y) { return (delete y[x]); }); }); _this.cols = Object.keys(changes.schema); _this.schema.properties = changes.schema; _this.schema.required = Object.keys(changes.schema); } if (changes.name) { if (database.tables.find(function (x) { return x.name == changes.name; })) throw new Error("Table \"".concat(changes.name, "\" already exists.")); _this.name = changes.name; } if (changes.autoId) { if (changes.autoId) { (_a = _this.rows) === null || _a === void 0 ? void 0 : _a.forEach(function (x) { x["id"] = _this.rows.length + 1; }); } else { (_b = _this.rows) === null || _b === void 0 ? void 0 : _b.forEach(function (x) { return (delete x["id"]); }); } _this.autoId = changes.autoId; } }; this.createRow = function (row) { Object.keys(row).forEach(function (x) { if (_this.schema.properties[x].type == "number") row[x] = parseInt(row[x]); }); if (!new ajv_1["default"]().compile(_this.schema)(row)) throw new Error("Error while inserting new row into \"".concat(_this.name, "\"\n ").concat(JSON.stringify(row), " does not match\n ").concat(JSON.stringify(_this.schema.properties), ".")); if (!_this.rows) _this.rows = []; if (_this.autoId) { row["id"] = _this.rows.length + 1; } _this.rows.push(row); }; this.name = name; this.cols = cols; if (rows) this.rows = rows; this.schema = schema; this.autoId = autoId ? true : false; } return Table; }()); exports.Table = Table; function encrypt(data, key) { var iv = crypto.randomBytes(16); key = crypto.createHash("md5").update(key).digest("hex"); var cipher = crypto.createCipheriv("aes-256-cbc", Buffer.from(key), iv); var encrypted = cipher.update(data); encrypted = Buffer.concat([encrypted, cipher.final()]); return { iv: iv.toString("hex"), encryptedData: encrypted.toString("hex") }; } function decrypt(data, key) { var iv = Buffer.from(data.iv, "hex"); key = crypto.createHash("md5").update(key).digest("hex"); var encryptedText = Buffer.from(data.encryptedData, "hex"); var decipher = crypto.createDecipheriv("aes-256-cbc", Buffer.from(key), iv); var decrypted = decipher.update(encryptedText); decrypted = Buffer.concat([decrypted, decipher.final()]); return decrypted.toString(); }