Implemented NeDB based repository
This commit is contained in:
parent
50f83b47d1
commit
1febe41516
|
@ -4,9 +4,16 @@ module.exports = {
|
|||
port: 3000,
|
||||
|
||||
nodeModulesPath: path.join(__dirname, 'node_modules'),
|
||||
userDatabasePath: path.join(__dirname, 'data', 'users'),
|
||||
fileUploadPath: path.join(__dirname, 'data', 'files'),
|
||||
fileUploadPublicPath: '/files',
|
||||
|
||||
database: {
|
||||
path: path.join(__dirname, 'data'),
|
||||
autocompactionInterval: 60000
|
||||
},
|
||||
|
||||
fileUpload: {
|
||||
path: path.join(__dirname, 'data', 'files'),
|
||||
url: '/files'
|
||||
},
|
||||
|
||||
jwtSecret: 'change me to a random generated string'
|
||||
};
|
58
index.js
58
index.js
|
@ -1,7 +1,7 @@
|
|||
'use strict'
|
||||
|
||||
const config = require('./config');
|
||||
const JsonUserDatabase = require('./lib/JsonUserDatabase');
|
||||
const Repository = require('./lib/repository');
|
||||
|
||||
const _ = require('lodash');
|
||||
const express = require('express');
|
||||
|
@ -15,20 +15,6 @@ const webpackDevMiddleware = require('webpack-dev-middleware');
|
|||
const webpackHotMiddleware = require('webpack-hot-middleware');
|
||||
const webpackConfig = require('./webpack.config.js');
|
||||
|
||||
/*
|
||||
function metadataToObject(stringValue)
|
||||
{
|
||||
const keyValuePairList = stringValue.split(',');
|
||||
|
||||
return _.reduce(keyValuePairList , (metadata, keyValuePair) => {
|
||||
let [key, base64Value] = keyValuePair.split(' ');
|
||||
metadata[key] = new Buffer(base64Value, "base64").toString("ascii");
|
||||
|
||||
return metadata;
|
||||
}, {});
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
function checkAuthorization(req, res, onVerified)
|
||||
{
|
||||
|
@ -56,35 +42,15 @@ function checkAuthorization(req, res, onVerified)
|
|||
{
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production';
|
||||
|
||||
const userDatabase = new JsonUserDatabase(config.userDatabasePath);
|
||||
await userDatabase.load();
|
||||
const repository = new Repository(config.database);
|
||||
|
||||
|
||||
const tusServer = new tus.Server();
|
||||
tusServer.datastore = new tus.FileStore({
|
||||
path: config.fileUploadPublicPath,
|
||||
directory: config.fileUploadPath
|
||||
path: config.fileUpload.url,
|
||||
directory: config.fileUpload.path
|
||||
});
|
||||
|
||||
/*
|
||||
tusServer.on(tus.EVENTS.EVENT_UPLOAD_COMPLETE, (event) =>
|
||||
{
|
||||
console.log(event);
|
||||
|
||||
const metadata = metadataToObject(event.file.upload_metadata);
|
||||
jwt.verify(metadata.token, config.jwtSecret, (err, decoded) =>
|
||||
{
|
||||
if (err)
|
||||
return;
|
||||
|
||||
const filePath = path.join(config.fileUploadPath, event.file.id);
|
||||
console.log(filePath);
|
||||
|
||||
// TODO save metadata for file and notify people
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
|
@ -100,10 +66,12 @@ function checkAuthorization(req, res, onVerified)
|
|||
return;
|
||||
}
|
||||
|
||||
if (await userDatabase.isValidCode(req.body.code))
|
||||
var userId = await repository.findCodeUserId(req.body.code);
|
||||
if (userId !== null)
|
||||
{
|
||||
jwt.sign({
|
||||
code: req.body.code
|
||||
code: req.body.code,
|
||||
userId: userId
|
||||
}, config.jwtSecret, (err, token) =>
|
||||
{
|
||||
if (err)
|
||||
|
@ -126,10 +94,12 @@ function checkAuthorization(req, res, onVerified)
|
|||
return;
|
||||
}
|
||||
|
||||
checkAuthorization(req, res, (decoded) =>
|
||||
checkAuthorization(req, res, async (decoded) =>
|
||||
{
|
||||
console.log(req.body.files);
|
||||
// TODO save set
|
||||
console.log('1');
|
||||
var uploadId = await repository.addUpload(decoded.userId, req.body.files);
|
||||
console.log(uploadId);
|
||||
res.send({ id: uploadId });
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
const debug = require('debug')('recv:JsonUserDatabase');
|
||||
const uuidv4 = require('uuid/v4');
|
||||
const fs = require('mz/fs');
|
||||
const mkdir = require('mkdir-promise');
|
||||
const path = require('path');
|
||||
|
||||
|
||||
class JsonUserDatabase
|
||||
{
|
||||
constructor(path)
|
||||
{
|
||||
this.path = path;
|
||||
|
||||
this.codes = {};
|
||||
this.users = {};
|
||||
}
|
||||
|
||||
|
||||
async load()
|
||||
{
|
||||
debug('loading database from ' + this.path);
|
||||
|
||||
try
|
||||
{
|
||||
var files = await fs.readdir(this.path);
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
if (err.code == 'ENOENT')
|
||||
// Path does not exist, no worries
|
||||
files = null;
|
||||
else
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (!files)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < files.length; i++)
|
||||
{
|
||||
var fullPath = path.join(this.path, files[i]);
|
||||
var stats = await fs.lstat(fullPath);
|
||||
|
||||
if (stats.isFile())
|
||||
{
|
||||
debug('loading ' + fullPath);
|
||||
try
|
||||
{
|
||||
var userInfo = JSON.parse(await fs.readFile(fullPath));
|
||||
if (userInfo.type !== 'user')
|
||||
throw new Error('unsupported file type: ' + userInfo.type);
|
||||
|
||||
this.users[userInfo.uid] = userInfo;
|
||||
}
|
||||
catch (err)
|
||||
{
|
||||
console.error('error while loading file ' + fullPath + ', skipped:');
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug(Object.keys(this.users).length + ' user(s) loaded');
|
||||
}
|
||||
|
||||
|
||||
addUser(info)
|
||||
{
|
||||
var userId = uuidv4();
|
||||
|
||||
// TODO add user
|
||||
// TODO save file
|
||||
|
||||
return userId;
|
||||
}
|
||||
|
||||
|
||||
isValidCode(code)
|
||||
{
|
||||
debug('validating code: ' + code);
|
||||
|
||||
// TODO check code
|
||||
var valid = true;
|
||||
|
||||
debug('valid = ' + valid);
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = JsonUserDatabase;
|
|
@ -0,0 +1,208 @@
|
|||
//const debug = require('debug')('recv:users');
|
||||
const _ = require('lodash');
|
||||
const path = require('path');
|
||||
const mkdirp = require('mkdirp');
|
||||
const bcrypt = require('bcrypt');
|
||||
const Datastore = require('nedb');
|
||||
const shortid = require('shortid');
|
||||
const retry = require('async-retry')
|
||||
|
||||
|
||||
class Repository
|
||||
{
|
||||
constructor(config)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
const initStore = (filename) =>
|
||||
{
|
||||
var store = new Datastore({
|
||||
filename: path.join(config.path, filename),
|
||||
autoload: true
|
||||
});
|
||||
|
||||
store.persistence.setAutocompactionInterval(config.autocompactionInterval);
|
||||
return store;
|
||||
};
|
||||
|
||||
mkdirp(config.path, (err) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
|
||||
self.db = {
|
||||
users: initStore('users.db'),
|
||||
codes: initStore('codes.db'),
|
||||
uploads: initStore('uploads.db')
|
||||
};
|
||||
|
||||
|
||||
// Initialize database if empty
|
||||
self.db.users.count({}, (err, count) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
self.addUser('admin', null, 'test');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async isValidUser(username, password)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
self.db.users.findOne({ username: username }, (err, doc) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (doc == null)
|
||||
{
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
bcrypt.compare(password, doc.password, (err, res) =>
|
||||
{
|
||||
if (err)
|
||||
reject(err)
|
||||
else
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async addUser(username, email, password)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
bcrypt.hash(password, 10, function(err, hash)
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
var user = {
|
||||
username: username,
|
||||
email: email,
|
||||
password: hash
|
||||
};
|
||||
|
||||
self.db.users.insert(user, (err, dbUser) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(dbUser._id);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async findCodeUserId(code)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
self.db.codes.findOne({ _id: code }, (err, doc) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(doc !== null ? doc.userId : null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async addCode(userId, expiration)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return await retry(async bail =>
|
||||
{
|
||||
var code = shortid.generate();
|
||||
|
||||
if ((await self.findCodeUserId(code)) !== null)
|
||||
throw new Error('Code ' + code + ' already exists');
|
||||
|
||||
self.db.codes.insert({
|
||||
_id: code,
|
||||
userId: userId,
|
||||
expiration: expiration
|
||||
})
|
||||
|
||||
return code;
|
||||
}, {
|
||||
retries: 100,
|
||||
minTimeout: 0,
|
||||
maxTimeout: 0
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async addUpload(userId, files)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
var upload = {
|
||||
files: _.map(_.filter(files,
|
||||
(file) => file.hasOwnProperty('id') && file.hasOwnProperty('name')),
|
||||
(file) => { return { id: file.id, name: file.name } })
|
||||
};
|
||||
console.log(upload);
|
||||
|
||||
if (upload.files.length)
|
||||
{
|
||||
self.db.uploads.insert(upload, (err, dbUpload) =>
|
||||
{
|
||||
console.log(dbUpload);
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(dbUpload._id);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = Repository;
|
12
package.json
12
package.json
|
@ -15,16 +15,18 @@
|
|||
"author": "Mark van Renswoude <mark@x2software.net>",
|
||||
"license": "Unlicense",
|
||||
"dependencies": {
|
||||
"async-retry": "^1.2.1",
|
||||
"bcrypt": "^1.0.3",
|
||||
"body-parser": "^1.18.2",
|
||||
"debug": "^3.1.0",
|
||||
"express": "^4.16.2",
|
||||
"jsonwebtoken": "^8.1.1",
|
||||
"mkdir-promise": "^1.0.0",
|
||||
"mz": "^2.7.0",
|
||||
"lodash": "^4.17.5",
|
||||
"mkdirp": "^0.5.1",
|
||||
"nedb": "^1.8.0",
|
||||
"npm": "^5.7.1",
|
||||
"tus-node-server": "^0.2.10",
|
||||
"uuid": "^3.2.1",
|
||||
"lodash": "^4.17.5"
|
||||
"shortid": "^2.2.8",
|
||||
"tus-node-server": "^0.2.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^0.18.0",
|
||||
|
|
|
@ -50,7 +50,7 @@ export default {
|
|||
self.code.checking = true;
|
||||
|
||||
axios.post('/token/upload', {
|
||||
code: self.code
|
||||
code: self.code.value
|
||||
})
|
||||
.then((response) =>
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue