molly-db
Version:
Molly-db is a free and open source library for nodejs that allow you create a lightweight encrypted database using Json files
357 lines (293 loc) • 12.3 kB
JavaScript
/*--────────────────────────────────────────────────────────────────────────────────────────────--*/
const crypto = require('./crypto_handler');
const init = require('./init_handler');
const path = require('path');
const output = new Object();
const fs = require('fs');
/*--────────────────────────────────────────────────────────────────────────────────────────────--*/
output.validator = function( db, params ){
return new Promise((response,reject)=>{
let validator = false; output.bodyParser( params );
const vdb = ()=>db._init_.DB.some(x=>x.name==params.db);
const vtb = ()=>db._init_.DB.some(x=>x.tables?.join().match(params.table));
validator = [
[ !params?.db, 'params.db = "test"' ],
[ !params?.offset, 'params.offset = 0' ],
[ !params?.target, 'params.target = ""' ],
[ !params?.length, 'params.length = 100' ],
[ !params?.table, 'params.table = "test"' ],
].every(x=>{ if(x[0]) eval(x[1]); return true; });
validator = [
[!params?.db, {status:404,message:'error: no db name added'}],
[!params?.table, {status:404,message:'error: no table name added'}],
].some(x=>{ if(x[0]) response([0,x[1]]); return x[0];}); if(validator) return 0;
validator = [
[!vdb(), output.addDB(params,db)],
[!vtb(), output.addTable(params,db)],
].some(x=>x[0]); response([1,'']);
});
}
/*--────────────────────────────────────────────────────────────────────────────────────────────--*/
const encryptDB = function( param, db, _db, _table, _path ){
return new Promise((response,reject)=>{
const writable = fs.createWriteStream( _path+'_tmp' );
for( var i in db[_db][_table] ){
const data = db[_db][_table][i];
const ecrp = crypto.encrypt( data,param.pass );
writable.write(`${ecrp}\n`);
} writable.end();
writable.on('error',(e)=>reject(e));
writable.on('close',()=>{
fs.renameSync( _path+'_tmp', _path );
response('done');
});
});
}
const modifyDB = async function( data, db, _name, _table ){
try{
const init = `${db._path_}/_init_.json`;
const dir = `${db._path_}/${_table}.json`;
fs.writeFileSync( init,JSON.stringify(db._init_) );
try{const length = db[_name][_table].length;
if( !(length>0) ) fs.writeFileSync(dir,'');
else await encryptDB( data, db, _name, _table, dir );
} catch(e) { fs.unlinkSync( dir ); }
} catch(e) { return parseError(db,data,e) }
}
const parseData = function( db,params,_data, _length ){
const length = _length||db[params.db][params.table].length;
const pagination = Math.ceil(length/_data.length)||1;
return {
status: 200, data: _data,
length: length, table: params.table,
pagination: pagination, database: params.db,
}
}
output.bodyParser = function( data ){
try{const date = Date.now(); const {body} = data;
const result = Array.isArray(body) ? body : [body];
data.body = result.map(x=>{ if( !x?.hash )
x.hash = crypto.hash( date,Math.random() );
return JSON.stringify(x);
});
} catch(e) { }
}
const parseError = function( db,params,_e ){
return {
status: 404,
table: params.table,
database: params.db,
data: _e.message||_e,
}
}
/*--────────────────────────────────────────────────────────────────────────────────────────────--*/
output.pop = function(data,db){ db._update_ = true;
const result = db[data.db][data.table].pop();
return parseData( db,data,result );
}
output.shift = function(data,db){ db._update_ = true;
const result = db[data.db][data.table].shift();
return parseData( db,data,result );
}
output.slice = function(data,db){
const result = db[data.db][data.table].slice(...data.args);
return parseData( db,data,result );
}
/*-- ── --*/
output.push = function( data,db ){ db._update_ = true;
const result = db[data.db][data.table].push(...data.body);
return parseData( db,data,result );
}
output.unshift = function( data,db ){ db._update_ = true;
const result = db[data.db][data.table].unshift(...data.body);
return parseData( db,data,result );
}
/*-- ── --*/
output.tableList = function( data,db ){
const result = Object.keys(db[data.db]);
return parseData( db,data,result );
}
/*
output.dbList = function( data,db ){
const result = Object.keys(db);
return parseData( db,data,result );
}
*/
/*-- ── --*/
output.list = function(data,db){
try{return parseData( db,data,
db[data.db][data.table].slice(
data.offset, Number(data.offset) + Number(data.length)
).map(x=> JSON.parse(x) )
);
} catch(e) { return parseError(db,data,e) }
}
output.hash = function(data,db){
try{const result = new Array();
db[data.db][data.table].map((x)=>{
const regex = new RegExp(data.target,'gi');
if( regex.test(x) ) result.push(x);
});
return parseData( db,data,
result.map(x=>JSON.parse(x)).slice(
data.offset, Number(data.offset) + Number(data.length)
), result.length);
} catch(e) { return parseError(db,data,e) }
}
output.match = function(data,db){
try{const result = new Array();
db[data.db][data.table].map((x)=>{
const reg = crypto.slugify(data.target);
const regex = new RegExp(reg,'gi');
const target = crypto.slugify(x);
if( regex.test(target) ) result.push(x);
});
return parseData( db,data,
result.map(x=>JSON.parse(x)).slice(
data.offset, Number(data.offset) + Number(data.length)
), result.length);
} catch(e) { return parseError(db,data,e) }
}
/*-- ── --*/
output.update = function(data,db){
try { db._update_ = true;
for( var i in db[data.db][data.table] ){
const regex = new RegExp(data.target,'gi');
if( regex.test(db[data.db][data.table][i]) )
return db[data.db][data.table].splice(i,1,...data.body);
}
} catch(e) { return parseError(db,data,e) }
}
output.remove = function(data,db){
try{ db._update_ = true;
for( var i in db[data.db][data.table] ){
const regex = new RegExp(data.target,'gi');
if( regex.test(db[data.db][data.table][i]) )
return db[data.db][data.table].splice(i,0);
}
} catch(e) { return parseError(db,data,e) }
}
/*-- ── --*/
output.addDB = function(data,db){
try{db._update_ = true;
if( db[data.db] ) return {
status: 404,
database: data.db,
table: data.table,
message: 'DB already exist'
};
db._init_.DB.push({
tables: [], name: data.db,
}); db[data.db] = new Array();
return {
status: 200,
message: 'DB added',
database: data.db,
};
} catch(e) { return parseError(db,data,e) }
}
output.removeDB = function(data,db){
try{
if( !db[data.db] ) return {
status: 404,
database: data.db,
table: data.table,
message: 'DB does not exist',
};
for( var i in db._init_.DB ){
if( db._init_.DB[i].name == data.db ){
db._init_.DB[i].tables.map(x=>{
const dir = `${data.path}/${x}.json`;
if( fs.existsSync(dir) ) fs.unlinkSync(dir);
});
const arr = db._init_.DB; arr.splice(i,1);
db._init_.DB = arr||new Array();
delete db[data.db];
break;
}
}
return {
status: 200,
database: data.db,
table: data.table,
message: 'DB deleted'
};
} catch(e) { return parseError(db,data,e) }
}
output.addTable = function(data,db){
try{db._update_ = true;
if( db[data.db][data.table] ) return {
status: 404,
database: data.db,
table: data.table,
message: 'table already exist',
};
for( var i in db._init_.DB ){
if( db._init_.DB[i].name == data.db ){
db[data.db][data.table] = new Array();
db._init_.DB[i].tables.push(data.table);
break;
}
}
return {
status: 200,
database: data.db,
table: data.table,
message: 'table added'
};
} catch(e) { return parseError(db,data,e) }
}
output.removeTable = function(data,db){
try{db._update_ = true;
if( !db[data.db][data.table] ) return {
status: 404,
database: data.db,
table: data.table,
message: 'table does not exist'
};
for( var i in db._init_.DB ){
if( db._init_.DB[i].name == data.db ){
const dir = `${data.path}/${data.table}.json`;
const j = db._init_.DB[i].tables.indexOf(data.table);
if( fs.existsSync(dir) ) fs.unlinkSync(dir);
const arr = db._init_.DB[i].tables; arr.splice(j,1);
db._init_.DB[i].tables = arr||new Array();
delete db[data.db][data.table];
}
}
return {
status: 200,
database: data.db,
table: data.table,
message: 'table removed'
};
} catch(e) { return parseError(db,data,e) }
}
/*--────────────────────────────────────────────────────────────────────────────────────────────--*/
output.saveAll = async function(data,db){
try { for( var i in db['_init_'] ){ for( var j in db['_init_'][i] ){
const { name, tables } = db['_init_'][i][j];
for( var k in tables ) await modifyDB(data,db,name,tables[k])
}} return {
status: 200,
database: data.db,
table: data.table,
message: 'DB Saved'
}} catch(e) { return parseError(db,data,e) }
}
/*--────────────────────────────────────────────────────────────────────────────────────────────--*/
output.reset = async function(data,db){
const args = JSON.parse(process.env.MOLLY_DB_ARGS);
return new Promise((response,reject)=>{
init( args ).then((ndb)=>{ db = ndb;
return response({
status: 200,
database: data.db,
table: data.table,
message: 'DB Reseted'
});
}).catch((e)=>{ response(parseError(db,data,e)) });
})
}
/*--────────────────────────────────────────────────────────────────────────────────────────────--*/
module.exports = output;