feat: new permission to allow users to see other users requests

closes #840
This commit is contained in:
sct
2021-02-04 12:40:00 +00:00
parent 06e941171a
commit 033ba9d41b
8 changed files with 62 additions and 20 deletions

View File

@@ -8,7 +8,11 @@ import {
RelationCount,
AfterLoad,
} from 'typeorm';
import { Permission, hasPermission } from '../lib/permissions';
import {
Permission,
hasPermission,
PermissionCheckOptions,
} from '../lib/permissions';
import { MediaRequest } from './MediaRequest';
import bcrypt from 'bcrypt';
import path from 'path';
@@ -85,8 +89,11 @@ export class User {
return filtered;
}
public hasPermission(permissions: Permission | Permission[]): boolean {
return !!hasPermission(permissions, this.permissions);
public hasPermission(
permissions: Permission | Permission[],
options?: PermissionCheckOptions
): boolean {
return !!hasPermission(permissions, this.permissions, options);
}
public passwordMatch(password: string): Promise<boolean> {

View File

@@ -13,6 +13,11 @@ export enum Permission {
REQUEST_4K_MOVIE = 2048,
REQUEST_4K_TV = 4096,
REQUEST_ADVANCED = 8192,
REQUEST_VIEW = 16384,
}
export interface PermissionCheckOptions {
type: 'and' | 'or';
}
/**
@@ -22,10 +27,12 @@ export enum Permission {
*
* @param permissions Single permission or array of permissions
* @param value users current permission value
* @param options Extra options to control permission check behavior (mainly for arrays)
*/
export const hasPermission = (
permissions: Permission | Permission[],
value: number
value: number,
options: PermissionCheckOptions = { type: 'and' }
): boolean => {
let total = 0;
@@ -35,8 +42,15 @@ export const hasPermission = (
}
if (Array.isArray(permissions)) {
// Combine all permission values into one
total = permissions.reduce((a, v) => a + v, 0);
if (value & Permission.ADMIN) {
return true;
}
switch (options.type) {
case 'and':
return permissions.every((permission) => !!(value & permission));
case 'or':
return permissions.some((permission) => !!(value & permission));
}
} else {
total = permissions;
}

View File

@@ -1,6 +1,6 @@
import { getRepository } from 'typeorm';
import { User } from '../entity/User';
import { Permission } from '../lib/permissions';
import { Permission, PermissionCheckOptions } from '../lib/permissions';
import { getSettings } from '../lib/settings';
export const checkUser: Middleware = async (req, _res, next) => {
@@ -34,10 +34,11 @@ export const checkUser: Middleware = async (req, _res, next) => {
};
export const isAuthenticated = (
permissions?: Permission | Permission[]
permissions?: Permission | Permission[],
options?: PermissionCheckOptions
): Middleware => {
const authMiddleware: Middleware = (req, res, next) => {
if (!req.user || !req.user.hasPermission(permissions ?? 0)) {
if (!req.user || !req.user.hasPermission(permissions ?? 0, options)) {
res.status(403).json({
status: 403,
error: 'You do not have permission to access this endpoint',

View File

@@ -57,7 +57,8 @@ requestRoutes.get('/', async (req, res, next) => {
}
const [requests, requestCount] = req.user?.hasPermission(
Permission.MANAGE_REQUESTS
[Permission.MANAGE_REQUESTS, Permission.REQUEST_VIEW],
{ type: 'or' }
)
? await requestRepository.findAndCount({
order: sortFilter,
@@ -102,10 +103,10 @@ requestRoutes.post(
if (
req.body.userId &&
!(
req.user?.hasPermission(Permission.MANAGE_USERS) &&
req.user?.hasPermission(Permission.MANAGE_REQUESTS)
)
!req.user?.hasPermission([
Permission.MANAGE_USERS,
Permission.MANAGE_REQUESTS,
])
) {
return next({
status: 403,