Browse Source

refactor: Replaced remaining backend admin checks with hasPermission

Owen Diffey 2 years ago
parent
commit
7a64ca3636

+ 29 - 57
backend/logic/actions/playlists.js

@@ -820,18 +820,10 @@ export default {
 
 				(playlist, next) => {
 					if (!playlist) return next("Playlist not found");
-					if (playlist.privacy !== "public" && playlist.createdBy !== session.userId) {
-						if (session)
-							// check if user requested to get a playlist is an admin
-							return DBModule.runJob("GET_MODEL", { modelName: "user" }, this).then(userModel => {
-								userModel.findOne({ _id: session.userId }, (err, user) => {
-									if (user && user.role === "admin") return next(null, playlist);
-									return next("User unauthorised to view playlist.");
-								});
-							});
-						return next("User unauthorised to view playlist.");
-					}
-
+					if (playlist.privacy !== "public" && playlist.createdBy !== session.userId)
+						return hasPermission("playlists.getPlaylist", session)
+							.then(() => next(null, playlist))
+							.catch(() => next("User unauthorised to view playlist."));
 					return next(null, playlist);
 				}
 			],
@@ -879,18 +871,10 @@ export default {
 
 				(playlist, next) => {
 					if (!playlist) return next("Playlist not found");
-					if (playlist.privacy !== "public" && playlist.createdBy !== session.userId) {
-						if (session)
-							// check if user requested to get a playlist is an admin
-							return DBModule.runJob("GET_MODEL", { modelName: "user" }, this).then(userModel => {
-								userModel.findOne({ _id: session.userId }, (err, user) => {
-									if (user && user.role === "admin") return next(null, playlist);
-									return next("User unauthorised to view playlist.");
-								});
-							});
-						return next("User unauthorised to view playlist.");
-					}
-
+					if (playlist.privacy !== "public")
+						return hasPermission("stations.getPlaylist", session, stationId)
+							.then(() => next(null, playlist))
+							.catch(() => next("User unauthorised to view playlist."));
 					return next(null, playlist);
 				}
 			],
@@ -1016,14 +1000,11 @@ export default {
 				next => {
 					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
-							if (!playlist || playlist.createdBy !== session.userId) {
-								return DBModule.runJob("GET_MODEL", { modelName: "user" }, this).then(userModel => {
-									userModel.findOne({ _id: session.userId }, (err, user) => {
-										if (user && user.role === "admin") return next();
-										return next("Something went wrong when trying to get the playlist");
-									});
-								});
-							}
+							if (!playlist) return next("Playlist not found.");
+							if (playlist.createdBy !== session.userId)
+								return hasPermission("playlists.repositionSong", session)
+									.then(() => next())
+									.catch(() => next("Invalid permissions."));
 							return next();
 						})
 						.catch(next);
@@ -1107,14 +1088,12 @@ export default {
 				next => {
 					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
-							if (!playlist || playlist.createdBy !== session.userId) {
-								DBModule.runJob("GET_MODEL", { modelName: "user" }, this).then(userModel => {
-									userModel.findOne({ _id: session.userId }, (err, user) => {
-										if (user && user.role === "admin") return next(null, playlist);
-										return next("Something went wrong when trying to get the playlist");
-									});
-								});
-							} else next(null, playlist);
+							if (!playlist) return next("Playlist not found.");
+							if (playlist.createdBy !== session.userId)
+								return hasPermission("playlists.addSongToPlaylist", session)
+									.then(() => next(null, playlist))
+									.catch(() => next("Invalid permissions."));
+							return next(null, playlist);
 						})
 						.catch(next);
 				},
@@ -1376,15 +1355,11 @@ export default {
 
 				(playlist, next) => {
 					this.publishProgress({ status: "update", message: `Importing YouTube playlist (stage 4)` });
-					if (!playlist || playlist.createdBy !== session.userId) {
-						return DBModule.runJob("GET_MODEL", { modelName: "user" }, this).then(userModel => {
-							userModel.findOne({ _id: session.userId }, (err, user) => {
-								if (user && user.role === "admin") return next(null, playlist);
-								return next("Something went wrong when trying to get the playlist");
-							});
-						});
-					}
-
+					if (!playlist) return next("Playlist not found.");
+					if (playlist.createdBy !== session.userId)
+						return hasPermission("playlists.addSetToPlaylist", session)
+							.then(() => next(null, playlist))
+							.catch(() => next("Invalid permissions."));
 					return next(null, playlist);
 				}
 			],
@@ -1459,14 +1434,11 @@ export default {
 				next => {
 					PlaylistsModule.runJob("GET_PLAYLIST", { playlistId }, this)
 						.then(playlist => {
-							if (!playlist || playlist.createdBy !== session.userId) {
-								return DBModule.runJob("GET_MODEL", { modelName: "user" }, this).then(userModel => {
-									userModel.findOne({ _id: session.userId }, (err, user) => {
-										if (user && user.role === "admin") return next(null, playlist);
-										return next("Something went wrong when trying to get the playlist");
-									});
-								});
-							}
+							if (!playlist) return next("Playlist not found.");
+							if (playlist.createdBy !== session.userId)
+								return hasPermission("playlists.removeSongFromPlaylist", session)
+									.then(() => next(null, playlist))
+									.catch(() => next("Invalid permissions."));
 							return next(null, playlist);
 						})
 						.catch(next);

+ 39 - 90
backend/logic/actions/stations.js

@@ -52,37 +52,13 @@ CacheModule.runJob("SUB", {
 					const socket = await WSModule.runJob("SOCKET_FROM_SOCKET_ID", { socketId }, this);
 					if (!socket) return;
 					const { session } = socket;
-
-					if (session.sessionId) {
-						CacheModule.runJob("HGET", {
-							table: "sessions",
-							key: session.sessionId
-						}).then(session => {
-							if (session)
-								DBModule.runJob(
-									"GET_MODEL",
-									{
-										modelName: "user"
-									},
-									this
-								).then(userModel => {
-									userModel.findOne({ _id: session.userId }, (err, user) => {
-										if (user && user.role === "admin")
-											socket.dispatch("event:station.userCount.updated", {
-												data: { stationId, count }
-											});
-										else if (
-											user &&
-											station.type === "community" &&
-											station.owner === session.userId
-										)
-											socket.dispatch("event:station.userCount.updated", {
-												data: { stationId, count }
-											});
-									});
-								});
-						});
-					}
+					hasPermission("stations.view", session, stationId)
+						.then(() => {
+							socket.dispatch("event:station.userCount.updated", {
+								data: { stationId, count }
+							});
+						})
+						.catch(() => {});
 				});
 			}
 		});
@@ -274,8 +250,6 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "station.create",
 	cb: async stationId => {
-		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" });
-
 		StationsModule.runJob("INITIALIZE_STATION", { stationId }).then(async res => {
 			const { station } = res;
 			station.userCount = StationsModule.usersPerStationCount[stationId] || 0;
@@ -299,22 +273,11 @@ CacheModule.runJob("SUB", {
 					const socket = await WSModule.runJob("SOCKET_FROM_SOCKET_ID", { socketId }, this);
 					if (!socket) return;
 					const { session } = socket;
-
-					if (session.sessionId) {
-						CacheModule.runJob("HGET", {
-							table: "sessions",
-							key: session.sessionId
-						}).then(session => {
-							if (session) {
-								userModel.findOne({ _id: session.userId }, (err, user) => {
-									if (user && user.role === "admin")
-										socket.dispatch("event:station.created", { data: { station } });
-									else if (user && station.type === "community" && station.owner === session.userId)
-										socket.dispatch("event:station.created", { data: { station } });
-								});
-							}
-						});
-					}
+					hasPermission("stations.view", session, stationId)
+						.then(() => {
+							socket.dispatch("event:station.created", { data: { station } });
+						})
+						.catch(() => {});
 				});
 			}
 		});
@@ -431,30 +394,26 @@ export default {
 											},
 											this
 										)
-											.then(exists => {
-												if (exists && session.userId && station.privacy !== "public") {
-													DBModule.runJob("GET_MODEL", { modelName: "user" }, this)
-														.then(userModel => {
-															userModel.findOne({ _id: session.userId }, (err, user) => {
-																if (err) return callback(err);
-																if (
-																	(user.role !== "admin" &&
-																		station.owner !== session.userId) ||
-																	(adminFilter &&
-																		user.role === "admin" &&
-																		station.owner !== session.userId)
-																) {
-																	return callback(null, false);
-																}
-																return callback(null, exists);
-															});
-														})
-														.catch(callback);
-												} else if (exists && !session.userId && station.privacy !== "public")
-													callback(null, false);
-												else callback(null, exists);
-											})
+											.then(exists => callback(null, exists))
 											.catch(callback);
+									},
+
+									(exists, callback) => {
+										if (!exists) callback(null, false, false);
+										else if (station.privacy === "public") callback(null, true, true);
+										else
+											hasPermission("stations.index", session.userId, station._id)
+												.then(() => callback(null, true, true))
+												.catch(() => callback(null, true, false));
+									},
+
+									(exists, canIndex, callback) => {
+										if (!exists) callback(null, false);
+										else if (!canIndex && !adminFilter)
+											hasPermission("stations.index.other", session.userId)
+												.then(() => callback(null, true))
+												.catch(() => callback(null, false));
+										else callback(null, canIndex);
 									}
 								],
 								(err, exists) => {
@@ -1239,7 +1198,7 @@ export default {
 		async.waterfall(
 			[
 				next => {
-					hasPermission("stations.forceSkip", session, stationId)
+					hasPermission("stations.skip", session, stationId)
 						.then(() => next())
 						.catch(next);
 				},
@@ -1662,7 +1621,6 @@ export default {
 	 * @param cb
 	 */
 	create: isLoginRequired(async function create(session, data, cb) {
-		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
 		const stationModel = await DBModule.runJob("GET_MODEL", { modelName: "station" }, this);
 		const playlistModel = await DBModule.runJob("GET_MODEL", { modelName: "playlist" }, this);
 
@@ -1734,14 +1692,10 @@ export default {
 					if (blacklist.indexOf(data.name) !== -1)
 						return next("That name is blacklisted. Please use a different name.");
 
-					if (data.type === "official") {
-						return userModel.findOne({ _id: session.userId }, (err, user) => {
-							if (err) return next(err);
-							if (!user) return next("User not found.");
-							if (user.role !== "admin") return next("Admin required.");
-							return next();
-						});
-					}
+					if (data.type === "official")
+						return hasPermission("stations.create.official", session)
+							.then(() => next())
+							.catch(() => next("Insufficient permissions."));
 					return next();
 				},
 
@@ -1838,8 +1792,6 @@ export default {
 	 * @param cb
 	 */
 	addToQueue: isLoginRequired(async function addToQueue(session, stationId, youtubeId, cb) {
-		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
-
 		async.waterfall(
 			[
 				next => {
@@ -1858,12 +1810,9 @@ export default {
 						station.requests.access === "owner" ||
 						(station.requests.access === "user" && station.privacy === "private")
 					) {
-						return userModel.findOne({ _id: session.userId }, (err, user) => {
-							if (err) return next(err);
-							if (user.role !== "admin" && station.owner !== session.userId)
-								return next("You do not have permission to add songs to queue.");
-							return next(null, station);
-						});
+						return hasPermission("stations.addToQueue", session, stationId)
+							.then(() => next(null, station))
+							.catch(() => next("You do not have permission to add songs to queue."));
 					}
 
 					return next(null, station);

+ 35 - 45
backend/logic/actions/users.js

@@ -7,7 +7,7 @@ import axios from "axios";
 import bcrypt from "bcrypt";
 import sha256 from "sha256";
 import isLoginRequired from "../hooks/loginRequired";
-import { useHasPermission } from "../hooks/hasPermission";
+import { hasPermission, useHasPermission } from "../hooks/hasPermission";
 
 // eslint-disable-next-line
 import moduleManager from "../../index";
@@ -1242,17 +1242,13 @@ export default {
 	 * @param {Function} cb - gets called with the result
 	 */
 	removeSessions: isLoginRequired(async function removeSessions(session, userId, cb) {
-		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
-
 		async.waterfall(
 			[
 				next => {
-					userModel.findOne({ _id: session.userId }, (err, user) => {
-						if (err) return next(err);
-						if (user.role !== "admin" && session.userId !== userId)
-							return next("Only admins and the owner of the account can remove their sessions.");
-						return next();
-					});
+					if (session.userId === userId) return next();
+					return hasPermission("users.removeSessions", session)
+						.then(() => next())
+						.catch(() => next("Only admins and the owner of the account can remove their sessions."));
 				},
 
 				next => {
@@ -1988,14 +1984,13 @@ export default {
 		async.waterfall(
 			[
 				next => {
-					if (updatingUserId === session.userId) return next(null, true);
-					return userModel.findOne({ _id: session.userId }, next);
+					if (updatingUserId === session.userId) return next();
+					return hasPermission("users.updateUsername", session)
+						.then(() => next())
+						.catch(() => next("Invalid permissions."));
 				},
 
-				(user, next) => {
-					if (user !== true && (!user || user.role !== "admin")) return next("Invalid permissions.");
-					return userModel.findOne({ _id: updatingUserId }, next);
-				},
+				next => userModel.findOne({ _id: updatingUserId }, next),
 
 				(user, next) => {
 					if (!user) return next("User not found.");
@@ -2081,14 +2076,13 @@ export default {
 		async.waterfall(
 			[
 				next => {
-					if (updatingUserId === session.userId) return next(null, true);
-					return userModel.findOne({ _id: session.userId }, next);
+					if (updatingUserId === session.userId) return next();
+					return hasPermission("users.updateEmail", session)
+						.then(() => next())
+						.catch(() => next("Invalid permissions."));
 				},
 
-				(user, next) => {
-					if (user !== true && (!user || user.role !== "admin")) return next("Invalid permissions.");
-					return userModel.findOne({ _id: updatingUserId }, next);
-				},
+				next => userModel.findOne({ _id: updatingUserId }, next),
 
 				(user, next) => {
 					if (!user) return next("User not found.");
@@ -2192,14 +2186,13 @@ export default {
 		async.waterfall(
 			[
 				next => {
-					if (updatingUserId === session.userId) return next(null, true);
-					return userModel.findOne({ _id: session.userId }, next);
+					if (updatingUserId === session.userId) return next();
+					return hasPermission("users.updateName", session)
+						.then(() => next())
+						.catch(() => next("Invalid permissions."));
 				},
 
-				(user, next) => {
-					if (user !== true && (!user || user.role !== "admin")) return next("Invalid permissions.");
-					return userModel.findOne({ _id: updatingUserId }, next);
-				},
+				next => userModel.findOne({ _id: updatingUserId }, next),
 
 				(user, next) => {
 					if (!user) return next("User not found.");
@@ -2263,14 +2256,13 @@ export default {
 		async.waterfall(
 			[
 				next => {
-					if (updatingUserId === session.userId) return next(null, true);
-					return userModel.findOne({ _id: session.userId }, next);
+					if (updatingUserId === session.userId) return next();
+					return hasPermission("users.updateLocation", session)
+						.then(() => next())
+						.catch(() => next("Invalid permissions."));
 				},
 
-				(user, next) => {
-					if (user !== true && (!user || user.role !== "admin")) return next("Invalid permissions.");
-					return userModel.findOne({ _id: updatingUserId }, next);
-				},
+				next => userModel.findOne({ _id: updatingUserId }, next),
 
 				(user, next) => {
 					if (!user) return next("User not found.");
@@ -2334,14 +2326,13 @@ export default {
 		async.waterfall(
 			[
 				next => {
-					if (updatingUserId === session.userId) return next(null, true);
-					return userModel.findOne({ _id: session.userId }, next);
+					if (updatingUserId === session.userId) return next();
+					return hasPermission("users.updateBio", session)
+						.then(() => next())
+						.catch(() => next("Invalid permissions."));
 				},
 
-				(user, next) => {
-					if (user !== true && (!user || user.role !== "admin")) return next("Invalid permissions.");
-					return userModel.findOne({ _id: updatingUserId }, next);
-				},
+				next => userModel.findOne({ _id: updatingUserId }, next),
 
 				(user, next) => {
 					if (!user) return next("User not found.");
@@ -2399,14 +2390,13 @@ export default {
 		async.waterfall(
 			[
 				next => {
-					if (updatingUserId === session.userId) return next(null, true);
-					return userModel.findOne({ _id: session.userId }, next);
+					if (updatingUserId === session.userId) return next();
+					return hasPermission("users.updateAvatar", session)
+						.then(() => next())
+						.catch(() => next("Invalid permissions."));
 				},
 
-				(user, next) => {
-					if (user !== true && (!user || user.role !== "admin")) return next("Invalid permissions.");
-					return userModel.findOne({ _id: updatingUserId }, next);
-				},
+				next => userModel.findOne({ _id: updatingUserId }, next),
 
 				(user, next) => {
 					if (!user) return next("User not found.");

+ 11 - 14
backend/logic/api.js

@@ -5,6 +5,8 @@ import crypto from "crypto";
 
 import CoreClass from "../core";
 
+import { hasPermission } from "./hooks/hasPermission";
+
 let AppModule;
 let DBModule;
 let PlaylistsModule;
@@ -127,29 +129,24 @@ class _APIModule extends CoreClass {
 					response.app.get("/export/playlist/:playlistId", async (req, res) => {
 						const { playlistId } = req.params;
 
-						const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" });
-
 						PlaylistsModule.runJob("GET_PLAYLIST", { playlistId })
 							.then(playlist => {
-								if (playlist.privacy === "public") res.json({ status: "success", playlist });
-								else {
+								if (!playlist) res.json({ status: "error", message: "Playlist not found." });
+								else if (playlist.privacy === "public") res.json({ status: "success", playlist });
+								else
 									isLoggedIn(req, res, () => {
 										if (playlist.createdBy === req.session.userId)
 											res.json({ status: "success", playlist });
-										else {
-											userModel.findOne({ _id: req.session.userId }, (err, user) => {
-												if (err) res.json({ status: "error", message: err.message });
-												else if (user.role === "admin")
-													res.json({ status: "success", playlist });
-												else
+										else
+											hasPermission("playlists.getPlaylist", req.session.userId)
+												.then(() => res.json({ status: "success", playlist }))
+												.catch(() =>
 													res.json({
 														status: "error",
 														message: "You're not allowed to download this playlist."
-													});
-											});
-										}
+													})
+												);
 									});
-								}
 							})
 							.catch(err => {
 								res.json({ status: "error", message: err.message });

+ 39 - 16
backend/logic/hooks/hasPermission.js

@@ -3,24 +3,23 @@ import async from "async";
 // eslint-disable-next-line
 import moduleManager from "../../index";
 
-const DBModule = moduleManager.modules.db;
-const CacheModule = moduleManager.modules.cache;
-const UtilsModule = moduleManager.modules.utils;
-const StationsModule = moduleManager.modules.stations;
-
 const permissions = {};
 permissions.dj = {
 	"test.queue.add": true,
 	"test.queue.remove": false,
-	"stations.forceSkip": true,
+	"stations.view": true,
+	"stations.skip": true,
 	"stations.pause": true,
 	"stations.resume": true,
+	"stations.addToQueue": true,
 	"stations.removeFromQueue": true,
 	"stations.repositionSongInQueue": true,
 	"stations.autofillPlaylist": true,
 	"stations.removeAutofillPlaylist": true,
 	"stations.blacklistPlaylist": true,
-	"stations.removeBlacklistedPlaylist": true
+	"stations.removeBlacklistedPlaylist": true,
+	"stations.index": true,
+	"stations.getPlaylist": true
 };
 permissions.owner = {
 	...permissions.dj,
@@ -63,6 +62,11 @@ permissions.moderator = {
 	"playlists.getData": true,
 	"playlists.searchOfficial": true,
 	"playlists.updatePrivacyAdmin": true,
+	"playlists.getPlaylist": true,
+	"playlists.repositionSong": true,
+	"playlists.addSongToPlaylist": true,
+	"playlists.addSetToPlaylist": true,
+	"playlists.removeSongFromPlaylist": true,
 	"punishments.getData": true,
 	"punishments.getPunishmentsForUser": true,
 	"punishments.findOne": true,
@@ -75,6 +79,9 @@ permissions.moderator = {
 	"stations.getData": true,
 	"stations.resetQueue": true,
 	"stations.remove": false,
+	"stations.index": false,
+	"stations.index.other": true,
+	"stations.create.official": true,
 	"youtube.getVideos": true,
 	"youtube.requestSetAdmin": true
 };
@@ -111,6 +118,13 @@ permissions.admin = {
 	"users.adminRequestPasswordReset": true,
 	"users.resendVerifyEmail": true,
 	"users.banUserById": true,
+	"users.removeSessions": true,
+	"users.updateUsername": true,
+	"users.updateEmail": true,
+	"users.updateName": true,
+	"users.updateLocation": true,
+	"users.updateBio": true,
+	"users.updateAvatar": true,
 	"utils.getModules": true,
 	"utils.getModule": true,
 	"youtube.getQuotaStatus": true,
@@ -123,6 +137,10 @@ permissions.admin = {
 };
 
 export const hasPermission = async (permission, session, stationId) => {
+	const CacheModule = moduleManager.modules.cache;
+	const DBModule = moduleManager.modules.db;
+	const StationsModule = moduleManager.modules.stations;
+	const UtilsModule = moduleManager.modules.utils;
 	const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
 
 	return new Promise((resolve, reject) => {
@@ -155,7 +173,7 @@ export const hasPermission = async (permission, session, stationId) => {
 					return StationsModule.runJob("GET_STATION", { stationId }, this)
 						.then(station => {
 							if (!station) return next("Station not found.");
-							if (station.type === "community" && station.owner === user._id)
+							if (station.type === "community" && station.owner === user._id.toString())
 								return next(null, [user.role, "owner"]);
 							// if (station.type === "community" && station.djs.find(userId))
 							// 	return next(null, [user.role, "dj"]);
@@ -175,18 +193,22 @@ export const hasPermission = async (permission, session, stationId) => {
 				}
 			],
 			async err => {
+				const userId = typeof session === "object" ? session.userId || session.sessionId : session;
 				if (err) {
 					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
-					// TODO
-					// this.log(
-					// 	"INFO",
-					// 	"HAS_PERMISSION",
-					// 	`User "${userId}" does not have required permission "${permission}". "${err}"`
-					// );
+					UtilsModule.log(
+						"INFO",
+						"HAS_PERMISSION",
+						`User "${userId}" does not have required permission "${permission}". "${err}"`
+					);
 					return reject(err);
 				}
-				// TODO
-				// this.log("INFO", "HAS_PERMISSION", `User "${userId}" has required permission "${permission}".`, false);
+				UtilsModule.log(
+					"INFO",
+					"HAS_PERMISSION",
+					`User "${userId}" has required permission "${permission}".`,
+					false
+				);
 				return resolve();
 			}
 		);
@@ -195,6 +217,7 @@ export const hasPermission = async (permission, session, stationId) => {
 
 export const useHasPermission = (options, destination) =>
 	async function useHasPermission(session, ...args) {
+		const UtilsModule = moduleManager.modules.utils;
 		const permission = typeof options === "object" ? options.permission : options;
 		const stationId = typeof options === "object" ? options.stationId : null;
 		const cb = args[args.length - 1];

+ 27 - 100
backend/logic/stations.js

@@ -2,6 +2,8 @@ import async from "async";
 
 import CoreClass from "../core";
 
+import { hasPermission } from "./hooks/hasPermission";
+
 let StationsModule;
 let CacheModule;
 let DBModule;
@@ -1006,31 +1008,16 @@ class _StationsModule extends CoreClass {
 							if (session.sessionId) {
 								CacheModule.runJob("HGET", { table: "sessions", key: session.sessionId }).then(
 									session => {
-										if (session) {
-											DBModule.runJob("GET_MODEL", { modelName: "user" }).then(userModel => {
-												userModel.findOne({ _id: session.userId }, (err, user) => {
-													if (!err && user) {
-														if (user.role === "admin")
-															socket.dispatch("event:station.nextSong", {
-																data: {
-																	stationId: station._id,
-																	currentSong
-																}
-															});
-														else if (
-															station.type === "community" &&
-															station.owner === session.userId
-														)
-															socket.dispatch("event:station.nextSong", {
-																data: {
-																	stationId: station._id,
-																	currentSong
-																}
-															});
+										hasPermission("stations.skip", session, station._id)
+											.then(() =>
+												socket.dispatch("event:station.nextSong", {
+													data: {
+														stationId: station._id,
+														currentSong
 													}
-												});
-											});
-										}
+												})
+											)
+											.catch(() => {});
 									}
 								);
 							}
@@ -1080,17 +1067,9 @@ class _StationsModule extends CoreClass {
 					},
 
 					next => {
-						DBModule.runJob("GET_MODEL", { modelName: "user" }, this).then(userModel => {
-							userModel.findOne({ _id: payload.userId }, next);
-						});
-					},
-
-					(user, next) => {
-						if (!user) return next("Not allowed");
-						if (user.role === "admin" || payload.station.owner === payload.userId) return next(true);
-						if (payload.station.type === "official") return next("Not allowed");
-
-						return next("Not allowed");
+						hasPermission("stations.view", payload.userId, payload.station._id)
+							.then(() => next(true))
+							.catch(() => next("Not allowed"));
 					}
 				],
 				async errOrResult => {
@@ -1187,71 +1166,19 @@ class _StationsModule extends CoreClass {
 										sockets,
 										1,
 										(socket, next) => {
-											const { session } = socket;
-
-											async.waterfall(
-												[
-													next => {
-														if (!session.sessionId) next("No session id");
-														else next();
-													},
-
-													next => {
-														CacheModule.runJob(
-															"HGET",
-															{
-																table: "sessions",
-																key: session.sessionId
-															},
-															this
-														)
-															.then(response => {
-																next(null, response);
-															})
-															.catch(next);
-													},
-
-													(session, next) => {
-														if (!session) next("No session");
-														else {
-															DBModule.runJob("GET_MODEL", { modelName: "user" }, this)
-																.then(userModel => {
-																	next(null, userModel);
-																})
-																.catch(next);
-														}
-													},
-
-													(userModel, next) => {
-														if (!userModel) next("No user model");
-														else
-															userModel.findOne(
-																{
-																	_id: session.userId
-																},
-																next
-															);
-													},
-
-													(user, next) => {
-														if (!user) next("No user found");
-														else if (user.role === "admin") {
-															socketsThatCan.push(socket);
-															next();
-														} else if (
-															payload.station.type === "community" &&
-															payload.station.owner === session.userId
-														) {
-															socketsThatCan.push(socket);
-															next();
-														}
-													}
-												],
-												err => {
-													if (err) socketsThatCannot.push(socket);
-													next();
-												}
-											);
+											if (!(socket.session && socket.session.sessionId)) {
+												socketsThatCannot.push(socket);
+												next();
+											} else
+												hasPermission("stations.view", socket.session, payload.station._id)
+													.then(() => {
+														socketsThatCan.push(socket);
+														next();
+													})
+													.catch(() => {
+														socketsThatCannot.push(socket);
+														next();
+													});
 										},
 										err => {
 											if (err) reject(err);