new admin api

This commit is contained in:
IrosTheBeggar 2020-12-07 21:47:15 -05:00
parent be8bd9cc5d
commit 0aa6fabdd9
3 changed files with 61 additions and 2 deletions

View File

@ -86,7 +86,8 @@ exports.serveIt = config => {
// Login functionality
program.auth = false;
if (program.users && Object.keys(program.users).length !== 0) {
require('./modules/login.js').setup(mstream, program, express);
require('./src/api/auth.js').setup(mstream, program);
require('./modules/login.js').setup(mstream, program);
program.auth = true;
} else {
program.users = {
@ -154,7 +155,6 @@ exports.serveIt = config => {
server.listen(program.port, program.address, () => {
const protocol = program.ssl && program.ssl.cert && program.ssl.key ? 'https' : 'http';
winston.info(`Access mStream locally: ${protocol}://${program.address}:${program.port}`);
winston.info(`Try the WinAmp Demo: ${protocol}://${program.address}:${program.port}/winamp`);
dbModule.runAfterBoot(program);
ddns.setup(program);

28
src/api/auth.js Normal file
View File

@ -0,0 +1,28 @@
const jwt = require('jsonwebtoken');
const Joi = require('joi');
const winston = require('winston');
const auth = require('../util/auth');
exports.setup = (mstream, program) => {
mstream.post('/api/v1/auth/login', async (req, res) => {
try {
const schema = Joi.object({
username: Joi.string().required(),
password: Joi.string().required()
});
await schema.validateAsync(req.body);
if (!program.users[req.body.username]) { throw 'user not found'; }
await auth.authenticateUser(program.users[req.body.username].password, program.users[req.body.username].salt, req.body.password)
res.json({
vpaths: program.users[req.body.username].vpaths,
token: jwt.sign({ username: req.body.username }, program.secret)
});
}catch (err) {
winston.warn(`Failed login attempt from ${req.ip}. Username: ${req.body.username}`);
setTimeout(() => { res.status(401).json({ error: 'Login Failed' }); }, 800);
}
});
}

31
src/util/auth.js Normal file
View File

@ -0,0 +1,31 @@
const crypto = require('crypto');
const hashConfig = {
hashBytes: 32,
saltBytes: 16,
iterations: 15000
};
exports.hashPassword = password => {
return new Promise((resolve, reject) => {
crypto.randomBytes(hashConfig.saltBytes, (err, salt) => {
if (err) { return reject('Failed to hash password'); }
crypto.pbkdf2(password, salt.toString('base64'), hashConfig.iterations, hashConfig.hashBytes, 'sha512', (err, hash) => {
if (err) { return reject('Failed to hash password'); }
resolve({ salt: salt.toString('base64'), hashPassword: hash.toString('base64') });
});
});
});
}
exports.authenticateUser = (password, salt, givenPassword) => {
return new Promise((resolve, reject) => {
crypto.pbkdf2(givenPassword, salt, hashConfig.iterations, hashConfig.hashBytes, 'sha512', (err, verifyHash) => {
if (err) { reject('Unknown Authentication Error'); }
if (verifyHash.toString('base64') !== password) {
return reject('Authentication Error: Passwords do not match');
}
resolve();
});
});
}