mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-04-11 21:01:27 +03:00
Added additional info when requests are rejected due to no auth
Added two additional auth methods: registering and logging in. They have minimal functionality right now Added auth module which will handle all auth-related requests
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -63,3 +63,4 @@ backend/appdata/archives/blacklist_audio.txt
|
|||||||
backend/appdata/archives/blacklist_video.txt
|
backend/appdata/archives/blacklist_video.txt
|
||||||
backend/appdata/logs/combined.log
|
backend/appdata/logs/combined.log
|
||||||
backend/appdata/logs/error.log
|
backend/appdata/logs/error.log
|
||||||
|
backend/appdata/users.json
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
var async = require('async');
|
var async = require('async');
|
||||||
const { uuid } = require('uuidv4');
|
const { uuid } = require('uuidv4');
|
||||||
var fs = require('fs-extra');
|
var fs = require('fs-extra');
|
||||||
|
var auth = require('./authentication/auth');
|
||||||
var winston = require('winston');
|
var winston = require('winston');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var youtubedl = require('youtube-dl');
|
var youtubedl = require('youtube-dl');
|
||||||
@@ -146,6 +147,9 @@ var descriptors = {};
|
|||||||
app.use(bodyParser.urlencoded({ extended: false }));
|
app.use(bodyParser.urlencoded({ extended: false }));
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
|
|
||||||
|
// use passport
|
||||||
|
app.use(auth.passport.initialize());
|
||||||
|
|
||||||
// objects
|
// objects
|
||||||
|
|
||||||
function File(id, title, thumbnailURL, isAudio, duration, url, uploader, size, path, upload_date) {
|
function File(id, title, thumbnailURL, isAudio, duration, url, uploader, size, path, upload_date) {
|
||||||
@@ -1253,6 +1257,7 @@ app.use(function(req, res, next) {
|
|||||||
} else if (req.path.includes('/api/video/') || req.path.includes('/api/audio/')) {
|
} else if (req.path.includes('/api/video/') || req.path.includes('/api/audio/')) {
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
|
logger.verbose(`Rejecting request - invalid API use for endpoint: ${req.path}. API key received: ${req.query.apiKey}`);
|
||||||
req.socket.end();
|
req.socket.end();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -2303,6 +2308,17 @@ app.get('/api/audio/:id', function(req , res){
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// user authentication
|
||||||
|
|
||||||
|
app.post('/api/auth/register'
|
||||||
|
, auth.registerUser);
|
||||||
|
app.post('/api/auth/login'
|
||||||
|
// , auth.passport.authenticate('basic',{session:false}) // causes challenge pop-up on 401
|
||||||
|
, auth.authenticateViaPassport
|
||||||
|
, auth.generateJWT
|
||||||
|
, auth.returnAuthResponse
|
||||||
|
);
|
||||||
|
|
||||||
app.use(function(req, res, next) {
|
app.use(function(req, res, next) {
|
||||||
//if the request is not html then move along
|
//if the request is not html then move along
|
||||||
var accept = req.accepts('html', 'json', 'xml');
|
var accept = req.accepts('html', 'json', 'xml');
|
||||||
|
|||||||
172
backend/authentication/auth.js
Normal file
172
backend/authentication/auth.js
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
const low = require('lowdb')
|
||||||
|
const FileSync = require('lowdb/adapters/FileSync');
|
||||||
|
const adapter = new FileSync('./appdata/users.json');
|
||||||
|
const db = low(adapter);
|
||||||
|
db.defaults(
|
||||||
|
{
|
||||||
|
users: []
|
||||||
|
}
|
||||||
|
).write();
|
||||||
|
|
||||||
|
/*************************
|
||||||
|
* Authentication module
|
||||||
|
************************/
|
||||||
|
var bcrypt = require('bcrypt');
|
||||||
|
const saltRounds = 10;
|
||||||
|
|
||||||
|
var jwt = require('jsonwebtoken');
|
||||||
|
const JWT_EXPIRATION = (60 * 60); // one hour
|
||||||
|
|
||||||
|
const { uuid } = require('uuidv4');
|
||||||
|
const SERVER_SECRET = uuid();
|
||||||
|
|
||||||
|
exports.passport = require('passport');
|
||||||
|
var BasicStrategy = require('passport-http').BasicStrategy;
|
||||||
|
|
||||||
|
/***************************************
|
||||||
|
* Register user with hashed password
|
||||||
|
**************************************/
|
||||||
|
exports.registerUser = function(req, res) {
|
||||||
|
console.log('got here');
|
||||||
|
var userid = req.body.userid;
|
||||||
|
var username = req.body.username;
|
||||||
|
var plaintextPassword = req.body.password;
|
||||||
|
|
||||||
|
bcrypt.hash(plaintextPassword, saltRounds)
|
||||||
|
.then(function(hash) {
|
||||||
|
// check if user exists
|
||||||
|
if (db.get('users').find({uid: userid}).value()) {
|
||||||
|
// user id is taken!
|
||||||
|
res.status(409).send('UID is already taken!');
|
||||||
|
} else if (db.get('users').find({name: username}).value()) {
|
||||||
|
// user name is taken!
|
||||||
|
res.status(409).send('User name is already taken!');
|
||||||
|
} else {
|
||||||
|
// add to db
|
||||||
|
db.get('users').push({
|
||||||
|
name: username,
|
||||||
|
uid: userid,
|
||||||
|
passhash: hash
|
||||||
|
}).write();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(result) {
|
||||||
|
res.send('registered');
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
if( err.code == 'ER_DUP_ENTRY' ) {
|
||||||
|
res.status(409).send('UserId already taken');
|
||||||
|
} else {
|
||||||
|
console.log('failed TO register User');
|
||||||
|
|
||||||
|
// res.writeHead(500, {'Content-Type':'text/plain'});
|
||||||
|
res.end(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************
|
||||||
|
* Login methods
|
||||||
|
**************************************/
|
||||||
|
|
||||||
|
/*************************************************
|
||||||
|
* This gets called when passport.authenticate()
|
||||||
|
* gets called.
|
||||||
|
*
|
||||||
|
* This checks that the credentials are valid.
|
||||||
|
* If so, passes the user info to the next middleware.
|
||||||
|
************************************************/
|
||||||
|
exports.passport.use(new BasicStrategy(
|
||||||
|
function(userid, plainTextPassword, done) {
|
||||||
|
// console.log('BasicStrategy: verifying credentials');
|
||||||
|
const user = db.get('users').find({uid: userid}).value();
|
||||||
|
if (user) {
|
||||||
|
var hashedPwd = user.passhash;
|
||||||
|
return bcrypt.compare(plainTextPassword, hashedPwd);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
/*************************************************************
|
||||||
|
* This is a wrapper for auth.passport.authenticate().
|
||||||
|
* We use this to change WWW-Authenticate header so
|
||||||
|
* the browser doesn't pop-up challenge dialog box by default.
|
||||||
|
* Browser's will pop-up up dialog when status is 401 and
|
||||||
|
* "WWW-Authenticate:Basic..."
|
||||||
|
*************************************************************/
|
||||||
|
exports.authenticateViaPassport = function(req, res, next) {
|
||||||
|
exports.passport.authenticate('basic',{session:false},
|
||||||
|
function(err, user, info) {
|
||||||
|
if(!user){
|
||||||
|
res.set('WWW-Authenticate', 'x'+info); // change to xBasic
|
||||||
|
res.status(401).send('Invalid Authentication');
|
||||||
|
} else {
|
||||||
|
req.user = user;
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)(req, res, next);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
* Generating/Signing a JWT token
|
||||||
|
* And attaches the user info into
|
||||||
|
* the payload to be sent on every
|
||||||
|
* request.
|
||||||
|
*********************************/
|
||||||
|
exports.generateJWT = function(req, res, next) {
|
||||||
|
var payload = {
|
||||||
|
exp: Math.floor(Date.now() / 1000) + JWT_EXPIRATION
|
||||||
|
, user: req.user,
|
||||||
|
// , role: role
|
||||||
|
};
|
||||||
|
req.token = jwt.sign(payload, SERVER_SECRET);
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.returnAuthResponse = function(req, res) {
|
||||||
|
res.status(200).json({
|
||||||
|
user: req.user,
|
||||||
|
token: req.token
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************
|
||||||
|
* Authorization: middleware that checks the
|
||||||
|
* JWT token for validity before allowing
|
||||||
|
* the user to access anything.
|
||||||
|
*
|
||||||
|
* It also passes the user object to the next
|
||||||
|
* middleware through res.locals
|
||||||
|
**************************************/
|
||||||
|
exports.ensureAuthenticatedElseError = function(req, res, next) {
|
||||||
|
var token = getToken(req.query);
|
||||||
|
if( token ) {
|
||||||
|
try {
|
||||||
|
var payload = jwt.verify(token, SERVER_SECRET);
|
||||||
|
// console.log('payload: ' + JSON.stringify(payload));
|
||||||
|
// check if user still exists in database if you'd like
|
||||||
|
res.locals.user = payload.user;
|
||||||
|
next();
|
||||||
|
} catch(err) {
|
||||||
|
res.status(401).send('Invalid Authentication');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(401).send('Missing Authorization header');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getToken(queryParams) {
|
||||||
|
if (queryParams && queryParams.jwt) {
|
||||||
|
var parted = queryParams.jwt.split(' ');
|
||||||
|
if (parted.length === 2) {
|
||||||
|
return parted[1];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user