mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-03-28 07:30:56 +03:00
Added roles and permissions system, as well as the ability to modify users and their roles
Downloads manager now uses device fingerprint as identifier rather than a randomly generated sessionID
This commit is contained in:
@@ -91,7 +91,25 @@ db.defaults(
|
||||
|
||||
users_db.defaults(
|
||||
{
|
||||
users: []
|
||||
users: [],
|
||||
roles: {
|
||||
"admin": {
|
||||
"permissions": [
|
||||
'filemanager',
|
||||
'settings',
|
||||
'subscriptions',
|
||||
'sharing',
|
||||
'advanced_download',
|
||||
'downloads_manager'
|
||||
]
|
||||
}, "user": {
|
||||
"permissions": [
|
||||
'filemanager',
|
||||
'subscriptions',
|
||||
'sharing'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
).write();
|
||||
|
||||
@@ -2737,7 +2755,7 @@ app.post('/api/auth/jwtAuth'
|
||||
);
|
||||
app.post('/api/auth/changePassword', optionalJwt, async (req, res) => {
|
||||
let user_uid = req.user.uid;
|
||||
let password = req.body.password;
|
||||
let password = req.body.new_password;
|
||||
let success = await auth_api.changeUserPassword(user_uid, password);
|
||||
res.send({success: success});
|
||||
});
|
||||
@@ -2746,6 +2764,81 @@ app.post('/api/auth/adminExists', async (req, res) => {
|
||||
res.send({exists: exists});
|
||||
});
|
||||
|
||||
// user management
|
||||
app.post('/api/getUsers', optionalJwt, async (req, res) => {
|
||||
let users = users_db.get('users').value();
|
||||
res.send({users: users});
|
||||
});
|
||||
app.post('/api/getRoles', optionalJwt, async (req, res) => {
|
||||
let roles = users_db.get('roles').value();
|
||||
res.send({roles: roles});
|
||||
});
|
||||
|
||||
app.post('/api/changeUser', optionalJwt, async (req, res) => {
|
||||
let change_obj = req.body.change_object;
|
||||
try {
|
||||
const user_db_obj = users_db.get('users').find({uid: change_obj.uid});
|
||||
if (change_obj.name) {
|
||||
user_db_obj.assign({name: change_obj.name}).write();
|
||||
}
|
||||
if (change_obj.role) {
|
||||
user_db_obj.assign({role: change_obj.role}).write();
|
||||
}
|
||||
res.send({success: true});
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
res.send({success: false});
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/deleteUser', optionalJwt, async (req, res) => {
|
||||
let uid = req.body.uid;
|
||||
try {
|
||||
let usersFileFolder = config_api.getConfigItem('ytdl_users_base_path');
|
||||
const user_folder = path.join(__dirname, usersFileFolder, uid);
|
||||
const user_db_obj = users_db.get('users').find({uid: uid});
|
||||
if (user_db_obj.value()) {
|
||||
// user exists, let's delete
|
||||
deleteFolderRecursive(user_folder);
|
||||
users_db.get('users').remove({uid: uid}).write();
|
||||
}
|
||||
res.send({success: true});
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
res.send({success: false});
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/changeUserPermissions', optionalJwt, async (req, res) => {
|
||||
const user_uid = req.body.user_uid;
|
||||
const permission = req.body.permission;
|
||||
const new_value = req.body.new_value;
|
||||
|
||||
if (!permission || !new_value) {
|
||||
res.sendStatus(400);
|
||||
return;
|
||||
}
|
||||
|
||||
const success = auth_api.changeUserPermissions(user_uid, permission, new_value);
|
||||
|
||||
res.send({success: success});
|
||||
});
|
||||
|
||||
app.post('/api/changeRolePermissions', optionalJwt, async (req, res) => {
|
||||
const role = req.body.role;
|
||||
const permission = req.body.permission;
|
||||
const new_value = req.body.new_value;
|
||||
|
||||
if (!permission || !new_value) {
|
||||
res.sendStatus(400);
|
||||
return;
|
||||
}
|
||||
|
||||
const success = auth_api.changeRolePermissions(role, permission, new_value);
|
||||
|
||||
res.send({success: success});
|
||||
});
|
||||
|
||||
app.use(function(req, res, next) {
|
||||
//if the request is not html then move along
|
||||
var accept = req.accepts('html', 'json', 'xml');
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const path = require('path');
|
||||
const config_api = require('../config');
|
||||
const consts = require('../consts');
|
||||
var subscriptions_api = require('../subscriptions')
|
||||
const fs = require('fs-extra');
|
||||
var jwt = require('jsonwebtoken');
|
||||
@@ -97,7 +98,9 @@ exports.registerUser = function(req, res) {
|
||||
},
|
||||
subscriptions: [],
|
||||
created: Date.now(),
|
||||
role: userid === 'admin' ? 'admin' : 'user'
|
||||
role: userid === 'admin' ? 'admin' : 'user',
|
||||
permissions: [],
|
||||
permission_overrides: []
|
||||
};
|
||||
// check if user exists
|
||||
if (users_db.get('users').find({uid: userid}).value()) {
|
||||
@@ -200,8 +203,7 @@ exports.authenticateViaPassport = function(req, res, next) {
|
||||
exports.generateJWT = function(req, res, next) {
|
||||
var payload = {
|
||||
exp: Math.floor(Date.now() / 1000) + JWT_EXPIRATION
|
||||
, user: req.user,
|
||||
// , role: role
|
||||
, user: req.user
|
||||
};
|
||||
req.token = jwt.sign(payload, SERVER_SECRET);
|
||||
next();
|
||||
@@ -210,7 +212,9 @@ exports.generateJWT = function(req, res, next) {
|
||||
exports.returnAuthResponse = function(req, res) {
|
||||
res.status(200).json({
|
||||
user: req.user,
|
||||
token: req.token
|
||||
token: req.token,
|
||||
permissions: exports.userPermissions(req.user.uid),
|
||||
available_permissions: consts['AVAILABLE_PERMISSIONS']
|
||||
});
|
||||
}
|
||||
|
||||
@@ -252,6 +256,40 @@ exports.changeUserPassword = async function(user_uid, new_pass) {
|
||||
});
|
||||
}
|
||||
|
||||
// change user permissions
|
||||
exports.changeUserPermissions = function(user_uid, permission, new_value) {
|
||||
try {
|
||||
const user_db_obj = users_db.get('users').find({uid: user_uid});
|
||||
user_db_obj.get('permissions').pull(permission).write();
|
||||
user_db_obj.get('permission_overrides').pull(permission).write();
|
||||
if (new_value === 'yes') {
|
||||
user_db_obj.get('permissions').push(permission).write();
|
||||
user_db_obj.get('permission_overrides').push(permission).write();
|
||||
} else if (new_value === 'no') {
|
||||
user_db_obj.get('permission_overrides').push(permission).write();
|
||||
}
|
||||
return true;
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// change role permissions
|
||||
exports.changeRolePermissions = function(role, permission, new_value) {
|
||||
try {
|
||||
const role_db_obj = users_db.get('roles').get(role);
|
||||
role_db_obj.get('permissions').pull(permission).write();
|
||||
if (new_value === 'yes') {
|
||||
role_db_obj.get('permissions').push(permission).write();
|
||||
}
|
||||
return true;
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
exports.adminExists = function() {
|
||||
return !!users_db.get('users').find({uid: 'admin'}).value();
|
||||
}
|
||||
@@ -410,6 +448,74 @@ exports.changeSharingMode = function(user_uid, file_uid, type, is_playlist, enab
|
||||
return success;
|
||||
}
|
||||
|
||||
exports.userHasPermission = function(user_uid, permission) {
|
||||
const user_obj = users_db.get('users').find({uid: user_uid}).value();
|
||||
const role = user_obj['role'];
|
||||
if (!role) {
|
||||
// role doesn't exist
|
||||
logger.error('Invalid role ' + role);
|
||||
return false;
|
||||
}
|
||||
const role_permissions = (users_db.get('roles').value())['permissions'];
|
||||
|
||||
const user_has_explicit_permission = user_obj['permissions'].includes(permission);
|
||||
const permission_in_overrides = user_obj['permission_overrides'].includes(permission);
|
||||
|
||||
// check if user has a negative/positive override
|
||||
if (user_has_explicit_permission && permission_in_overrides) {
|
||||
// positive override
|
||||
return true;
|
||||
} else if (!user_has_explicit_permission && permission_in_overrides) {
|
||||
// negative override
|
||||
return false;
|
||||
}
|
||||
|
||||
// no overrides, let's check if the role has the permission
|
||||
if (role_permissions.includes(permission)) {
|
||||
return true;
|
||||
} else {
|
||||
logger.verbose(`User ${user_uid} failed to get permission ${permission}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
exports.userPermissions = function(user_uid) {
|
||||
let user_permissions = [];
|
||||
const user_obj = users_db.get('users').find({uid: user_uid}).value();
|
||||
const role = user_obj['role'];
|
||||
if (!role) {
|
||||
// role doesn't exist
|
||||
logger.error('Invalid role ' + role);
|
||||
return null;
|
||||
}
|
||||
const role_permissions = users_db.get('roles').get(role).get('permissions').value()
|
||||
|
||||
for (let i = 0; i < consts['AVAILABLE_PERMISSIONS'].length; i++) {
|
||||
let permission = consts['AVAILABLE_PERMISSIONS'][i];
|
||||
|
||||
const user_has_explicit_permission = user_obj['permissions'].includes(permission);
|
||||
const permission_in_overrides = user_obj['permission_overrides'].includes(permission);
|
||||
|
||||
// check if user has a negative/positive override
|
||||
if (user_has_explicit_permission && permission_in_overrides) {
|
||||
// positive override
|
||||
user_permissions.push(permission);
|
||||
} else if (!user_has_explicit_permission && permission_in_overrides) {
|
||||
// negative override
|
||||
continue;
|
||||
}
|
||||
|
||||
// no overrides, let's check if the role has the permission
|
||||
if (role_permissions.includes(permission)) {
|
||||
user_permissions.push(permission);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return user_permissions;
|
||||
}
|
||||
|
||||
function getToken(queryParams) {
|
||||
if (queryParams && queryParams.jwt) {
|
||||
var parted = queryParams.jwt.split(' ');
|
||||
|
||||
@@ -142,7 +142,17 @@ let CONFIG_ITEMS = {
|
||||
},
|
||||
};
|
||||
|
||||
AVAILABLE_PERMISSIONS = [
|
||||
'filemanager',
|
||||
'settings',
|
||||
'subscriptions',
|
||||
'sharing',
|
||||
'advanced_download',
|
||||
'downloads_manager'
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
CONFIG_ITEMS: CONFIG_ITEMS,
|
||||
AVAILABLE_PERMISSIONS: AVAILABLE_PERMISSIONS,
|
||||
CURRENT_VERSION: 'v3.6'
|
||||
}
|
||||
Reference in New Issue
Block a user