molly-db 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Enmanuel D Becerra C
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,199 @@
1
+ # LWDB : lightweight Database
2
+
3
+ lw-db is a free and open source library for nodejs that allow you create a lightweight encrypted database using Json files
4
+
5
+ # Usage
6
+
7
+ ### init lwdb on nodeJS
8
+ ```
9
+
10
+ const lwdb = require('lwdb');
11
+
12
+ ldb = new lwdb.createLocalDB( '/PATH/TO/DATA/BASE' ); // for non encrypted data
13
+
14
+ // or
15
+
16
+ ldb = new lwdb.createLocalDB( '/PATH/TO/DATA/BASE', 'PASSWORD' ); // for encrypted data
17
+
18
+ ```
19
+
20
+ ### init lwdb on Browser
21
+ ```
22
+
23
+ <script type="text/javascript" src="https://molly-js.github.io/MollyJS-Libs/molly.js" ></script>
24
+
25
+ <script type="text/javascript">
26
+ require( libs.crypto, libs.lwdb )
27
+ .then( ()=>{
28
+ ldb = new lwdb.createWebDB( 'PASSWORD' );
29
+ } )
30
+ </script>
31
+
32
+ ```
33
+
34
+ ### get an item list from a table
35
+ ```
36
+ let table = 'tableName' //NOTE: if table doesn't exist lwdb generates a new one
37
+
38
+ let config = { offset:0, length:10 }
39
+
40
+ ldb.list( table,config )
41
+ .then( (response)=>{
42
+ console.log( response );
43
+ })
44
+ ```
45
+
46
+ ### fing from a target object
47
+ ```
48
+ let table = 'test';
49
+
50
+ let target = {
51
+ name:'Peter'
52
+ }
53
+
54
+ let logic = 'AND' or 'OR'
55
+
56
+ let config = { // optional
57
+ offset:0, length:10
58
+ }
59
+
60
+ ldb.find( table,target,logic,config )
61
+ .then( (response)=>{
62
+ console.log( response );
63
+ });
64
+
65
+ ```
66
+
67
+ ### find by matching
68
+ ```
69
+ let table = 'test';
70
+
71
+ let match = 'peter'
72
+
73
+ let config = { // optional
74
+ offset:0, length:10
75
+ }
76
+
77
+ ldb.match( table,match,config )
78
+ .then( (response)=>{
79
+ console.log( response );
80
+ });
81
+
82
+ ```
83
+
84
+ ### find by hash
85
+ ```
86
+ let table = 'test';
87
+
88
+ let hash = 'SHA256_TEST'
89
+
90
+ let config = { // optional
91
+ offset:0, length:10
92
+ }
93
+
94
+ ldb.findByHash( table,hash,config )
95
+ .then( (response)=>{
96
+ console.log( response );
97
+ });
98
+
99
+ ```
100
+
101
+ ### push a new item at the end
102
+ ```
103
+ let table = 'test';
104
+
105
+ let object = {
106
+ name:'Peter',
107
+ S: 'Male',
108
+ age: 23,
109
+ }
110
+
111
+ ldb.push(table,object)
112
+ .then( ()=>{ /* once finish */ });
113
+
114
+ ```
115
+
116
+ ### push a new item at the beginning
117
+ ```
118
+ let table = 'test';
119
+
120
+ let object = {
121
+ name:'Peter',
122
+ S: 'Male',
123
+ age: 23,
124
+ }
125
+
126
+ ldb.unshift(table,object)
127
+ .then( ()=>{ /* once finish */ });
128
+
129
+ ```
130
+
131
+ ### place a new item in the middle
132
+ ```
133
+ let table = 'test';
134
+
135
+ let line = 5; //if exist
136
+
137
+ let object = {
138
+ name:'Peter',
139
+ S: 'Male',
140
+ age: 23,
141
+ }
142
+
143
+ ldb.place(table,line,object)
144
+ .then( ()=>{ /* once finish */ });
145
+
146
+ ```
147
+
148
+ ### replace an item
149
+ ```
150
+ let table = 'test';
151
+
152
+ let hash = 'SHA256_TEST'
153
+
154
+ let object = {
155
+ name:'Peter',
156
+ S: 'Male',
157
+ age: 23,
158
+ }
159
+
160
+ ldb.replace(table,hash,object)
161
+ .then( ()=>{ /* once finish */ });
162
+
163
+ ```
164
+
165
+ ### remove an item
166
+ ```
167
+ let table = 'test';
168
+
169
+ let hash = 'SHA256_TEST'
170
+
171
+ ldb.remove(table,hash)
172
+ .then( ()=>{ /* once finish */ });
173
+
174
+ ```
175
+
176
+ ### remove the last item
177
+ ```
178
+ let table = 'test';
179
+
180
+ ldb.pop(table)
181
+ .then( ()=>{ /* once finish */ });
182
+ ```
183
+
184
+ ### remove the first item
185
+ ```
186
+ let table = 'test';
187
+
188
+ ldb.shift(table)
189
+ .then( ()=>{ /* once finish */ });
190
+ ```
191
+
192
+ ### remove a table
193
+ ```
194
+ let table = 'test';
195
+
196
+ ldb.removeTable(table)
197
+ .then( ()=>{ /* once finish */ });
198
+
199
+ ```
package/main.js ADDED
@@ -0,0 +1,8 @@
1
+ const output = new Object();
2
+
3
+ try{ output.streamDB = require('./module/streamDB'); } catch(e) { /*console.log(e)*/ }
4
+ try{ output.mongoDB = require('./module/mongoDB'); } catch(e) { /*console.log(e)*/ }
5
+ try{ output.localDB = require('./module/localDB'); } catch(e) { /*console.log(e)*/ }
6
+ try{ output.webDB = require('./module/webDB'); } catch(e) { /*console.log(e)*/ }
7
+
8
+ module.exports = output;
@@ -0,0 +1,437 @@
1
+ const readline = require('readline');
2
+ const crypto = require('crypto-js');
3
+ const fs = require('fs');
4
+
5
+ //TODO: Function ---------------------------------------------------------------------------------//
6
+ function slugify(str){
7
+ const map = {
8
+ 'o' : 'ó|ò|ô|õ|ö|Ó|Ò|Ô|Õ|Ö',
9
+ 'a' : 'á|à|ã|â|ä|À|Á|Ã|Â|Ä',
10
+ 'e' : 'é|è|ê|ë|É|È|Ê|Ë',
11
+ 'i' : 'í|ì|î|ï|Í|Ì|Î|Ï',
12
+ 'u' : 'ú|ù|û|ü|Ú|Ù|Û|Ü',
13
+ 'c' : 'ç|Ç','n':'ñ|Ñ',
14
+ '' : /\s+|\W+/,
15
+ };
16
+ for (var pattern in map) {
17
+ str=str.replace( new RegExp(map[pattern],'gi' ), pattern);
18
+ } return str.toLowerCase();
19
+ }
20
+
21
+ const JsonFormatter = {
22
+ 'stringify': function(cipherParams) {
23
+ var jsonObj = { ct: cipherParams.ciphertext.toString(crypto.enc.Base64) };
24
+ if (cipherParams.salt) jsonObj.s = cipherParams.salt.toString();
25
+ if (cipherParams.iv) jsonObj.iv = cipherParams.iv.toString();
26
+ return new Buffer(JSON.stringify(jsonObj)).toString('base64');
27
+ },
28
+
29
+ 'parse': function(jsonStr) {
30
+ var jsonObj = JSON.parse( new Buffer(jsonStr,'base64').toString('UTF-8'));
31
+ var cipherParams = crypto.lib.CipherParams.create({
32
+ ciphertext: crypto.enc.Base64.parse(jsonObj.ct)
33
+ });
34
+ if (jsonObj.iv) cipherParams.iv = crypto.enc.Hex.parse(jsonObj.iv);
35
+ if (jsonObj.s) cipherParams.salt = crypto.enc.Hex.parse(jsonObj.s);
36
+ return cipherParams;
37
+ }
38
+ };
39
+
40
+ //TODO: Optimization FUnctions -------------------------------------------------------------------//
41
+
42
+ const init = function( _table,_config,_self ){
43
+ return {
44
+ _itr: readline.createInterface( createNewTable( `${_self.path}/${_table}.json` ) ),
45
+ _cfg: !_config ? _self.default : _config,
46
+ _tmp: `${_self.path}/${_table}_tmp.json`,
47
+ _path: `${_self.path}/${_table}.json`,
48
+ _res: new Array(),
49
+ _i: 0,
50
+ }
51
+ };
52
+
53
+ const lineConstrain = function( _i,_config ){
54
+ if( _i >= parseInt(_config.length)+parseInt(_config.offset) ) return 1;
55
+ else if ( _i < parseInt(_config.offset) ) return -1
56
+ else return 0;
57
+ }
58
+
59
+ const createNewTable = function( _path ){
60
+ if( !fs.existsSync( _path ) ) fs.writeFileSync( _path,"" );
61
+ const table = fs.createReadStream( _path );
62
+ return { debug: false, input: table };
63
+ }
64
+
65
+ const createNewHash = function( _object ){
66
+ _object['_stamp'] = Date.now();
67
+ const _base = JSON.stringify( _object );
68
+ if( !_object.hash )
69
+ _object.hash = crypto.SHA256( _base ).toString();
70
+ return _object;
71
+ }
72
+
73
+ //TODO: localDB Class ----------------------------------------------------------------------------//
74
+
75
+ class localDB{
76
+
77
+ encrypted = false
78
+ events = new Object()
79
+ default = { offset: 0, length: 100 }
80
+
81
+ constructor( _path, _password ){
82
+ if( _password ){
83
+ this.password = _password;
84
+ this.encrypted = true;
85
+ } this.path = _path;
86
+ }
87
+
88
+ // TODO: Encription & Decription DATA //
89
+ encrypt( _message,_password=this.password,_encrypted=this.encrypted ){
90
+ try{
91
+ if( _encrypted )
92
+ return crypto.AES.encrypt( _message,_password,{
93
+ format: JsonFormatter
94
+ }).toString(); return _message;
95
+ } catch(e) { return _message; }
96
+ }
97
+
98
+ decrypt( _message,_password=this.password,_encrypted=this.encrypted ){
99
+ try{
100
+ if( _encrypted )
101
+ return crypto.AES.decrypt( _message,_password,{
102
+ format: JsonFormatter
103
+ }).toString( crypto.enc.Utf8 );
104
+ return _message;
105
+ } catch(e) { return _message; }
106
+ }
107
+
108
+ // TODO: Searching functions //
109
+ list( _table, _config ){
110
+ return new Promise( (res,rej)=>{ try{
111
+
112
+ let { _i,_cfg,_itr,_res,_tmp,_path } = init( _table,_config,this );
113
+
114
+ _itr.on( 'line',( encryptedLine )=>{ try{
115
+ const line = this.decrypt( encryptedLine );
116
+ const cns = lineConstrain( _i, _cfg );
117
+ if( cns == 0 ) { _res.push( JSON.parse( line ) );
118
+ } else if( cns == 1 ) _itr.close();
119
+ } catch(e) { rej(`the db can be decripted: ${e}`) }
120
+ _i++; });
121
+
122
+ _itr.on( 'close',()=>{ res({
123
+ table:_table,
124
+ data:_res,
125
+ }); });
126
+
127
+ } catch(e) { rej( e ); } });
128
+ }
129
+
130
+ on( _event, _callback ){ this.events[_event] = _callback; }
131
+ loop( _table ){
132
+ return new Promise( (res,rej)=>{ try{
133
+
134
+ let { _i,_cfg,_itr,_res,_tmp,_path } = init( _table,null,this );
135
+ if( this.events.start ) this.events.start( _itr );
136
+
137
+ _itr.on( 'line',( encryptedLine )=>{ try{
138
+ const line = this.decrypt( encryptedLine );
139
+ if( this.events.data ) this.events.data( line,_i,_itr );
140
+ } catch(e) { rej(`the db can be decripted: ${e}`) }
141
+ _i++; });
142
+
143
+ _itr.on( 'close',()=>{
144
+ if( this.events.close ) this.events.close( _itr );
145
+ });
146
+
147
+ } catch(e) { rej( e ); } });
148
+ }
149
+
150
+ find( _table, _target, _logic='AND', _config ){
151
+ return new Promise( async(res,rej)=>{ try{
152
+
153
+ let { _i,_cfg,_itr,_res } = await init( _table,_config,this );
154
+
155
+ _itr.on( 'line',( encryptedLine )=>{
156
+ try{
157
+ const line = this.decrypt( encryptedLine );
158
+ const keys = Object.keys( _target );
159
+ const data = JSON.parse( line );
160
+
161
+ const regex = ( x )=>{
162
+ const target = slugify(_target[x].toString());
163
+ const info = slugify(data[x].toString());
164
+ const regex = new RegExp(target,'gi');
165
+ return regex.test(info);
166
+ }
167
+
168
+ const every = keys.every( (x)=>{return regex(x)} );
169
+ const some = keys.some( (x)=>{return regex(x)} );
170
+
171
+ if( ( (/AND/gi).test(_logic) && every ) || ( (/OR/gi).test(_logic) && some ) ){
172
+ const cns = lineConstrain( _i, _cfg );
173
+ if( cns == 0 ) _res.push( data );
174
+ else if( cns == 1 ) _itr.close();
175
+ _i++;}
176
+
177
+ } catch(e) { rej(`the db can be decripted: ${e}`) }
178
+ });
179
+
180
+ _itr.on( 'close',()=>{ res({
181
+ table:_table,
182
+ data:_res,
183
+ }); });
184
+
185
+ } catch(e) { rej( e ); } });
186
+ }
187
+
188
+ match( _table,_match,_config ){
189
+ return new Promise( async(res,rej)=>{ try{
190
+
191
+ let { _i,_cfg,_itr,_res } = await init( _table,_config,this );
192
+
193
+ _itr.on( 'line',( encryptedLine )=>{ try{
194
+ const regex = new RegExp(slugify(_match),'gi');
195
+ const line = this.decrypt( encryptedLine );
196
+ if( regex.test(slugify(line)) ){
197
+ const cns = lineConstrain( _i, _cfg );
198
+ if( cns == 0 ) _res.push( JSON.parse( line ) );
199
+ else if( cns == 1 ) _itr.close();
200
+ _i++;}
201
+ } catch(e) { rej(`the db can be decripted: ${e}`) }
202
+ });
203
+
204
+ _itr.on( 'close',()=>{ res({
205
+ table:_table,
206
+ data:_res,
207
+ }); });
208
+
209
+ } catch(e) { rej( e ); } });
210
+ }
211
+
212
+ findByHash( _table, _hash ){
213
+ return new Promise( (res,rej)=>{ try{
214
+
215
+ let { _i,_cfg,_itr,_res,_tmp,_path } = init( _table,null,this );
216
+
217
+ _itr.on( 'line',( encryptedLine )=>{ try{
218
+ const line = this.decrypt( encryptedLine );
219
+ const data = JSON.parse( line );
220
+ if( data.hash == _hash ){
221
+ _res.push( data );
222
+ _itr.close();
223
+ }
224
+ } catch(e) { rej(`the db can be decripted: ${e}`) }
225
+ });
226
+
227
+ _itr.on( 'close',()=>{ res({
228
+ table:_table,
229
+ data:_res,
230
+ }); });
231
+
232
+ } catch(e) { rej( e ); } });
233
+ }
234
+
235
+ // TODO: Saving functions //
236
+ encryptTable( _table,_password ){
237
+ return new Promise( (res,rej)=>{ try{
238
+
239
+ let { _i,_cfg,_itr,_res,_tmp,_path } = init( _table,null,this );
240
+ const writable = fs.createWriteStream( _tmp );
241
+
242
+ writable.on( 'finish',()=>{ fs.renameSync( _tmp, _path ); res(); });
243
+
244
+ _itr.on( 'line',( encryptedLine )=>{
245
+ try{
246
+ const line = this.decrypt( encryptedLine );
247
+ const encryptedData = this.encrypt( line,_password,true );
248
+ writable.write( `${encryptedData}\n` );
249
+ } catch(e) { rej(`the db can be decripted ${e}`) }
250
+ });
251
+
252
+ _itr.on( 'close',()=>{ writable.end(); res({
253
+ table: _table,
254
+ }); });
255
+
256
+ } catch(e) { rej( e ); } });
257
+ }
258
+
259
+ decryptTable( _table ){
260
+ return new Promise( (res,rej)=>{ try{
261
+
262
+ let { _i,_cfg,_itr,_res,_tmp,_path } = init( _table,null,this );
263
+ const writable = fs.createWriteStream( _tmp );
264
+
265
+ writable.on( 'finish',()=>{ fs.renameSync( _tmp, _path ); res(); });
266
+ _itr.on( 'line',( encryptedLine )=>{
267
+ try{
268
+ const line = this.decrypt( encryptedLine );
269
+ writable.write( `${line}\n` );
270
+
271
+ } catch(e) { rej(`the db can be decripted: ${e}`) }
272
+ });
273
+
274
+ _itr.on( 'close',()=>{ writable.end(); res({
275
+ table: _table,
276
+ }); });
277
+
278
+ } catch(e) { rej( e ); } });
279
+ }
280
+
281
+ // TODO: Saving functions //
282
+ push( _table, ..._object ){
283
+ return new Promise( (res,rej)=>{ try{
284
+
285
+ let { _i,_cfg,_itr,_res,_tmp,_path } = init( _table,null,this );
286
+ const writable = fs.createWriteStream( _tmp );
287
+
288
+ _itr.on( 'line',( line )=>{ writable.write(`${line}\n`); });
289
+
290
+ _itr.on( 'close',()=>{
291
+ _object.flat().forEach( item=>{
292
+ item = createNewHash( item );
293
+ const encryptedData = this.encrypt( JSON.stringify( item ) );
294
+ writable.write( `${encryptedData}\n` );
295
+ }); writable.end();
296
+ });
297
+
298
+ writable.on( 'finish',()=>{ fs.renameSync( _tmp, _path ); res({
299
+ table: _table,
300
+ }); });
301
+
302
+ } catch(e) { rej(e); }
303
+ }); }
304
+
305
+ unshift( _table, ..._object ){
306
+ return new Promise( (res,rej)=>{ try{
307
+
308
+ let { _i,_cfg,_itr,_res,_tmp,_path } = init( _table,null,this );
309
+ const writable = fs.createWriteStream( _tmp );
310
+
311
+ _itr.on( 'line',( line )=>{
312
+ if( _i == 0 ){
313
+ _object.flat().forEach( item=>{
314
+ item = createNewHash( item );
315
+ const encryptedData = this.encrypt( JSON.stringify( item ) );
316
+ writable.write( `${encryptedData}\n` );
317
+ });
318
+ } writable.write( `${line}\n` );
319
+ _i++;});
320
+
321
+ _itr.on( 'close',()=>{ writable.end(); });
322
+
323
+ writable.on( 'finish',()=>{ fs.renameSync( _tmp, _path ); res({
324
+ table: _table,
325
+ }); });
326
+
327
+ } catch(e) { rej(e) }
328
+ }); }
329
+
330
+ place( _table, _line, ..._object ){
331
+ return new Promise( (res,rej)=>{ try{
332
+
333
+ let { _i,_cfg,_itr,_res,_tmp,_path } = init( _table,null,this );
334
+ const writable = fs.createWriteStream( _tmp );
335
+
336
+ _itr.on( 'line',( line )=>{
337
+ if( _i == _line ){
338
+ _object.flat().forEach( item=>{
339
+ item = createNewHash( item );
340
+ const encryptedData = this.encrypt( JSON.stringify( item ) );
341
+ writable.write( `${encryptedData}\n` );
342
+ });
343
+ } writable.write( `${line}\n` );
344
+ _i++;});
345
+
346
+ _itr.on( 'close',()=>{ writable.end(); });
347
+
348
+ writable.on( 'finish',()=>{ fs.renameSync( _tmp, _path ); res({
349
+ table: _table,
350
+ }); });
351
+
352
+ } catch(e) { rej(e) }
353
+ }); }
354
+
355
+ update( _table, _hash, ..._object ){
356
+ return new Promise( (res,rej)=>{ try{
357
+
358
+ let { _i,_cfg,_itr,_res,_tmp,_path } = init( _table,null,this );
359
+ const writable = fs.createWriteStream( _tmp );
360
+
361
+ _itr.on( 'line',( encryptedLine )=>{ try{
362
+ const line = this.decrypt( encryptedLine );
363
+ const data = JSON.parse( line );
364
+ if( data.hash == _hash ){
365
+ _object.flat().forEach( item=>{
366
+ item = createNewHash( item );
367
+ const encryptedData = this.encrypt( JSON.stringify( item ) );
368
+ writable.write( `${encryptedData}\n` );
369
+ });
370
+ } else
371
+ writable.write( `${encryptedLine}\n` );
372
+ } catch(e) { rej(`the db can be decripted: ${e}`) }
373
+ });
374
+
375
+ _itr.on( 'close',()=>{ writable.end(); });
376
+
377
+ writable.on( 'finish',()=>{ fs.renameSync( _tmp, _path ); res({
378
+ table: _table,
379
+ }); });
380
+
381
+ } catch(e) { rej(e) }
382
+ }); }
383
+
384
+ // TODO: Removing functions //
385
+ remove( _table, _hash ){
386
+ return new Promise( (res,rej)=>{ try{
387
+
388
+ let { _i,_cfg,_itr,_res,_tmp,_path } = init( _table,null,this );
389
+ const writable = fs.createWriteStream( _tmp );
390
+
391
+ _itr.on( 'line',( encryptedLine )=>{
392
+ const line = this.decrypt( encryptedLine );
393
+ const data = JSON.parse( line );
394
+ if( data.hash != _hash )
395
+ writable.write( `${encryptedLine}\n` );
396
+ });
397
+
398
+ _itr.on( 'close',()=>{ writable.end(); });
399
+
400
+ writable.on( 'finish',()=>{ fs.renameSync( _tmp, _path ); res({
401
+ table: _table,
402
+ }); });
403
+
404
+ } catch(e) { rej(e) }
405
+ }); }
406
+
407
+ removeTable( _table ){
408
+ return new Promise( (res,rej)=>{
409
+ const _path = `${this.path}/${_table}`;
410
+ fs.unlink( _path,( err,data )=>{
411
+ if(err) rej( err );
412
+ res({ table: _table });
413
+ });
414
+ })
415
+ }
416
+
417
+ shift( _table ){
418
+ return new Promise( (res,rej)=>{ try{
419
+
420
+ let { _i,_cfg,_itr,_res,_tmp,_path } = init( _table,null,this );
421
+ const writable = fs.createWriteStream( _tmp );
422
+
423
+ _itr.on( 'line',( line )=>{ if( _i != 0 ) writable.write( `${line}\n` ); _i++;});
424
+
425
+ _itr.on( 'close',()=>{ writable.end(); });
426
+
427
+ writable.on( 'finish',()=>{ fs.renameSync( _tmp, _path ); res({
428
+ table: _table,
429
+ }); });
430
+
431
+ } catch(e) { rej(e) }
432
+ }); }
433
+
434
+ }
435
+
436
+ //TODO: localDB Class ----------------------------------------------------------------------------//
437
+ module.exports = localDB;