Browse Source

fix: fixed security vulnerability where users could spoof userId's in socket.io in some cases

Kristian Vos 5 years ago
parent
commit
6861ec7969

+ 4 - 4
backend/logic/actions/apis.js

@@ -58,13 +58,13 @@ module.exports = {
 	 * @param artist - an artist for that song
 	 * @param cb
 	 */
-	getSpotifySongs: hooks.adminRequired((session, title, artist, cb, userId) => {
+	getSpotifySongs: hooks.adminRequired((session, title, artist, cb) => {
 		async.waterfall([
 			(next) => {
 				utils.getSongsFromSpotify(title, artist, next);
 			}
 		], (songs) => {
-			logger.success('APIS_GET_SPOTIFY_SONGS', `User "${userId}" got Spotify songs for title "${title}" successfully.`);
+			logger.success('APIS_GET_SPOTIFY_SONGS', `User "${session.userId}" got Spotify songs for title "${title}" successfully.`);
 			cb({status: 'success', songs: songs});
 		});
 	}),
@@ -76,7 +76,7 @@ module.exports = {
 	 * @param query - the query
 	 * @param cb
 	 */
-	searchDiscogs: hooks.adminRequired((session, query, page, cb, userId) => {
+	searchDiscogs: hooks.adminRequired((session, query, page, cb) => {
 		async.waterfall([
 			(next) => {
 				const params = [
@@ -106,7 +106,7 @@ module.exports = {
 				logger.error("APIS_SEARCH_DISCOGS", `Searching discogs failed with query "${query}". "${err}"`);
 				return cb({status: 'failure', message: err});
 			}
-			logger.success('APIS_SEARCH_DISCOGS', `User "${userId}" searched Discogs succesfully for query "${query}".`);
+			logger.success('APIS_SEARCH_DISCOGS', `User "${session.userId}" searched Discogs succesfully for query "${query}".`);
 			cb({status: 'success', results: body.results, pages: body.pagination.pages});
 		});
 	}),

+ 0 - 1
backend/logic/actions/hooks/adminRequired.js

@@ -33,7 +33,6 @@ module.exports = function(next) {
 				return cb({status: 'failure', message: err});
 			}
 			logger.info("ADMIN_REQUIRED", `User "${session.userId}" passed admin required check.`, false);
-			args.push(session.userId);
 			next.apply(null, args);
 		});
 	}

+ 0 - 1
backend/logic/actions/hooks/loginRequired.js

@@ -27,7 +27,6 @@ module.exports = function(next) {
 				return cb({status: 'failure', message: err});
 			}
 			logger.info("LOGIN_REQUIRED", `User "${session.userId}" passed login required check.`, false);
-			args.push(session.userId);
 			next.apply(null, args);
 		});
 	}

+ 0 - 1
backend/logic/actions/hooks/ownerRequired.js

@@ -39,7 +39,6 @@ module.exports = function(next) {
 				return cb({status: 'failure', message: err});
 			}
 			logger.info("OWNER_REQUIRED", `User "${session.userId}" passed owner required check for station "${stationId}"`, false);
-			args.push(session.userId);
 			next.apply(null, args);
 		});
 	}

+ 8 - 9
backend/logic/actions/news.js

@@ -64,12 +64,11 @@ module.exports = {
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {Object} data - the object of the news data
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	create: hooks.adminRequired((session, data, cb, userId) => {
+	create: hooks.adminRequired((session, data, cb) => {
 		async.waterfall([
 			(next) => {
-				data.createdBy = userId;
+				data.createdBy = session.userId;
 				data.createdAt = Date.now();
 				db.models.news.create(data, next);
 			}
@@ -116,15 +115,15 @@ module.exports = {
 	 */
 	//TODO Pass in an id, not an object
 	//TODO Fix this
-	remove: hooks.adminRequired((session, news, cb, userId) => {
+	remove: hooks.adminRequired((session, news, cb) => {
 		db.models.news.deleteOne({ _id: news._id }, async err => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("NEWS_REMOVE", `Removing news "${news._id}" failed for user "${userId}". "${err}"`);
+				logger.error("NEWS_REMOVE", `Removing news "${news._id}" failed for user "${session.userId}". "${err}"`);
 				return cb({ 'status': 'failure', 'message': err });
 			} else {
 				cache.pub('news.remove', news);
-				logger.success("NEWS_REMOVE", `Removing news "${news._id}" successful by user "${userId}".`);
+				logger.success("NEWS_REMOVE", `Removing news "${news._id}" successful by user "${session.userId}".`);
 				return cb({ 'status': 'success', 'message': 'Successfully removed News' });
 			}
 		});
@@ -139,15 +138,15 @@ module.exports = {
 	 * @param {Function} cb - gets called with the result
 	 */
 	//TODO Fix this
-	update: hooks.adminRequired((session, _id, news, cb, userId) => {
+	update: hooks.adminRequired((session, _id, news, cb) => {
 		db.models.news.updateOne({ _id }, news, { upsert: true }, async err => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("NEWS_UPDATE", `Updating news "${_id}" failed for user "${userId}". "${err}"`);
+				logger.error("NEWS_UPDATE", `Updating news "${_id}" failed for user "${session.userId}". "${err}"`);
 				return cb({ 'status': 'failure', 'message': err });
 			} else {
 				cache.pub('news.update', news);
-				logger.success("NEWS_UPDATE", `Updating news "${_id}" successful for user "${userId}".`);
+				logger.success("NEWS_UPDATE", `Updating news "${_id}" successful for user "${session.userId}".`);
 				return cb({ 'status': 'success', 'message': 'Successfully updated News' });
 			}
 		});

+ 53 - 65
backend/logic/actions/playlists.js

@@ -80,25 +80,24 @@ let lib = {
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {String} playlistId - the id of the playlist we are getting the first song from
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	getFirstSong: hooks.loginRequired((session, playlistId, cb, userId) => {
+	getFirstSong: hooks.loginRequired((session, playlistId, cb) => {
 		async.waterfall([
 			(next) => {
 				playlists.getPlaylist(playlistId, next);
 			},
 
 			(playlist, next) => {
-				if (!playlist || playlist.createdBy !== userId) return next('Playlist not found.');
+				if (!playlist || playlist.createdBy !== session.userId) return next('Playlist not found.');
 				next(null, playlist.songs[0]);
 			}
 		], async (err, song) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("PLAYLIST_GET_FIRST_SONG", `Getting the first song of playlist "${playlistId}" failed for user "${userId}". "${err}"`);
+				logger.error("PLAYLIST_GET_FIRST_SONG", `Getting the first song of playlist "${playlistId}" failed for user "${session.userId}". "${err}"`);
 				return cb({ status: 'failure', message: err});
 			}
-			logger.success("PLAYLIST_GET_FIRST_SONG", `Successfully got the first song of playlist "${playlistId}" for user "${userId}".`);
+			logger.success("PLAYLIST_GET_FIRST_SONG", `Successfully got the first song of playlist "${playlistId}" for user "${session.userId}".`);
 			cb({
 				status: 'success',
 				song: song
@@ -111,20 +110,19 @@ let lib = {
 	 *
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	indexForUser: hooks.loginRequired((session, cb, userId) => {
+	indexForUser: hooks.loginRequired((session, cb) => {
 		async.waterfall([
 			(next) => {
-				db.models.playlist.find({ createdBy: userId }, next);
+				db.models.playlist.find({ createdBy: session.userId }, next);
 			}
 		], async (err, playlists) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("PLAYLIST_INDEX_FOR_USER", `Indexing playlists for user "${userId}" failed. "${err}"`);
+				logger.error("PLAYLIST_INDEX_FOR_USER", `Indexing playlists for user "${session.userId}" failed. "${err}"`);
 				return cb({ status: 'failure', message: err});
 			}
-			logger.success("PLAYLIST_INDEX_FOR_USER", `Successfully indexed playlists for user "${userId}".`);
+			logger.success("PLAYLIST_INDEX_FOR_USER", `Successfully indexed playlists for user "${session.userId}".`);
 			cb({
 				status: 'success',
 				data: playlists
@@ -138,9 +136,8 @@ let lib = {
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {Object} data - the data for the new private playlist
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	create: hooks.loginRequired((session, data, cb, userId) => {
+	create: hooks.loginRequired((session, data, cb) => {
 		async.waterfall([
 
 			(next) => {
@@ -152,7 +149,7 @@ let lib = {
 				db.models.playlist.create({
 					displayName,
 					songs,
-					createdBy: userId,
+					createdBy: session.userId,
 					createdAt: Date.now()
 				}, next);
 			}
@@ -160,11 +157,11 @@ let lib = {
 		], async (err, playlist) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("PLAYLIST_CREATE", `Creating private playlist failed for user "${userId}". "${err}"`);
+				logger.error("PLAYLIST_CREATE", `Creating private playlist failed for user "${session.userId}". "${err}"`);
 				return cb({ status: 'failure', message: err});
 			}
 			cache.pub('playlist.create', playlist._id);
-			logger.success("PLAYLIST_CREATE", `Successfully created private playlist for user "${userId}".`);
+			logger.success("PLAYLIST_CREATE", `Successfully created private playlist for user "${session.userId}".`);
 			cb({ status: 'success', message: 'Successfully created playlist', data: {
 				_id: playlist._id
 			} });
@@ -177,25 +174,24 @@ let lib = {
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {String} playlistId - the id of the playlist we are getting
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	getPlaylist: hooks.loginRequired((session, playlistId, cb, userId) => {
+	getPlaylist: hooks.loginRequired((session, playlistId, cb) => {
 		async.waterfall([
 			(next) => {
 				playlists.getPlaylist(playlistId, next);
 			},
 
 			(playlist, next) => {
-				if (!playlist || playlist.createdBy !== userId) return next('Playlist not found');
+				if (!playlist || playlist.createdBy !== session.userId) return next('Playlist not found');
 				next(null, playlist);
 			}
 		], async (err, playlist) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("PLAYLIST_GET", `Getting private playlist "${playlistId}" failed for user "${userId}". "${err}"`);
+				logger.error("PLAYLIST_GET", `Getting private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`);
 				return cb({ status: 'failure', message: err});
 			}
-			logger.success("PLAYLIST_GET", `Successfully got private playlist "${playlistId}" for user "${userId}".`);
+			logger.success("PLAYLIST_GET", `Successfully got private playlist "${playlistId}" for user "${session.userId}".`);
 			cb({
 				status: 'success',
 				data: playlist
@@ -211,12 +207,11 @@ let lib = {
 	 * @param {String} playlistId - the id of the playlist we are updating
 	 * @param {Object} playlist - the new private playlist object
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	update: hooks.loginRequired((session, playlistId, playlist, cb, userId) => {
+	update: hooks.loginRequired((session, playlistId, playlist, cb) => {
 		async.waterfall([
 			(next) => {
-				db.models.playlist.updateOne({ _id: playlistId, createdBy: userId }, playlist, {runValidators: true}, next);
+				db.models.playlist.updateOne({ _id: playlistId, createdBy: session.userId }, playlist, {runValidators: true}, next);
 			},
 
 			(res, next) => {
@@ -225,10 +220,10 @@ let lib = {
 		], async (err, playlist) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("PLAYLIST_UPDATE", `Updating private playlist "${playlistId}" failed for user "${userId}". "${err}"`);
+				logger.error("PLAYLIST_UPDATE", `Updating private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`);
 				return cb({ status: 'failure', message: err});
 			}
-			logger.success("PLAYLIST_UPDATE", `Successfully updated private playlist "${playlistId}" for user "${userId}".`);
+			logger.success("PLAYLIST_UPDATE", `Successfully updated private playlist "${playlistId}" for user "${session.userId}".`);
 			cb({
 				status: 'success',
 				data: playlist
@@ -243,13 +238,12 @@ let lib = {
 	 * @param {String} songId - the id of the song we are trying to add
 	 * @param {String} playlistId - the id of the playlist we are adding the song to
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	addSongToPlaylist: hooks.loginRequired((session, songId, playlistId, cb, userId) => {
+	addSongToPlaylist: hooks.loginRequired((session, songId, playlistId, cb) => {
 		async.waterfall([
 			(next) => {
 				playlists.getPlaylist(playlistId, (err, playlist) => {
-					if (err || !playlist || playlist.createdBy !== userId) return next('Something went wrong when trying to get the playlist');
+					if (err || !playlist || playlist.createdBy !== session.userId) return next('Something went wrong when trying to get the playlist');
 
 					async.each(playlist.songs, (song, next) => {
 						if (song.songId === songId) return next('That song is already in the playlist');
@@ -285,11 +279,11 @@ let lib = {
 		async (err, playlist, newSong) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("PLAYLIST_ADD_SONG", `Adding song "${songId}" to private playlist "${playlistId}" failed for user "${userId}". "${err}"`);
+				logger.error("PLAYLIST_ADD_SONG", `Adding song "${songId}" to private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`);
 				return cb({ status: 'failure', message: err});
 			} else {
-				logger.success("PLAYLIST_ADD_SONG", `Successfully added song "${songId}" to private playlist "${playlistId}" for user "${userId}".`);
-				cache.pub('playlist.addSong', { playlistId: playlist._id, song: newSong, userId });
+				logger.success("PLAYLIST_ADD_SONG", `Successfully added song "${songId}" to private playlist "${playlistId}" for user "${session.userId}".`);
+				cache.pub('playlist.addSong', { playlistId: playlist._id, song: newSong, userId: session.userId });
 				return cb({ status: 'success', message: 'Song has been successfully added to the playlist', data: playlist.songs });
 			}
 		});
@@ -302,9 +296,8 @@ let lib = {
 	 * @param {String} url - the url of the the YouTube playlist
 	 * @param {String} playlistId - the id of the playlist we are adding the set of songs to
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	addSetToPlaylist: hooks.loginRequired((session, url, playlistId, cb, userId) => {
+	addSetToPlaylist: hooks.loginRequired((session, url, playlistId, cb) => {
 		async.waterfall([
 			(next) => {
 				utils.getPlaylistFromYouTube(url, songs => {
@@ -328,16 +321,16 @@ let lib = {
 			},
 
 			(playlist, next) => {
-				if (!playlist || playlist.createdBy !== userId) return next('Playlist not found.');
+				if (!playlist || playlist.createdBy !== session.userId) return next('Playlist not found.');
 				next(null, playlist);
 			}
 		], async (err, playlist) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("PLAYLIST_IMPORT", `Importing a YouTube playlist to private playlist "${playlistId}" failed for user "${userId}". "${err}"`);
+				logger.error("PLAYLIST_IMPORT", `Importing a YouTube playlist to private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`);
 				return cb({ status: 'failure', message: err});
 			} else {
-				logger.success("PLAYLIST_IMPORT", `Successfully imported a YouTube playlist to private playlist "${playlistId}" for user "${userId}".`);
+				logger.success("PLAYLIST_IMPORT", `Successfully imported a YouTube playlist to private playlist "${playlistId}" for user "${session.userId}".`);
 				cb({ status: 'success', message: 'Playlist has been successfully imported.', data: playlist.songs });
 			}
 		});
@@ -350,9 +343,8 @@ let lib = {
 	 * @param {String} songId - the id of the song we are removing from the private playlist
 	 * @param {String} playlistId - the id of the playlist we are removing the song from
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	removeSongFromPlaylist: hooks.loginRequired((session, songId, playlistId, cb, userId) => {
+	removeSongFromPlaylist: hooks.loginRequired((session, songId, playlistId, cb) => {
 		async.waterfall([
 			(next) => {
 				if (!songId || typeof songId !== 'string') return next('Invalid song id.');
@@ -365,7 +357,7 @@ let lib = {
 			},
 
 			(playlist, next) => {
-				if (!playlist || playlist.createdBy !== userId) return next('Playlist not found');
+				if (!playlist || playlist.createdBy !== session.userId) return next('Playlist not found');
 				db.models.playlist.updateOne({_id: playlistId}, {$pull: {songs: {songId: songId}}}, next);
 			},
 
@@ -375,11 +367,11 @@ let lib = {
 		], async (err, playlist) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("PLAYLIST_REMOVE_SONG", `Removing song "${songId}" from private playlist "${playlistId}" failed for user "${userId}". "${err}"`);
+				logger.error("PLAYLIST_REMOVE_SONG", `Removing song "${songId}" from private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`);
 				return cb({ status: 'failure', message: err});
 			} else {
-				logger.success("PLAYLIST_REMOVE_SONG", `Successfully removed song "${songId}" from private playlist "${playlistId}" for user "${userId}".`);
-				cache.pub('playlist.removeSong', { playlistId: playlist._id, songId: songId, userId });
+				logger.success("PLAYLIST_REMOVE_SONG", `Successfully removed song "${songId}" from private playlist "${playlistId}" for user "${session.userId}".`);
+				cache.pub('playlist.removeSong', { playlistId: playlist._id, songId: songId, userId: session.userId });
 				return cb({ status: 'success', message: 'Song has been successfully removed from playlist', data: playlist.songs });
 			}
 		});
@@ -391,12 +383,11 @@ let lib = {
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {String} playlistId - the id of the playlist we are updating the displayName for
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	updateDisplayName: hooks.loginRequired((session, playlistId, displayName, cb, userId) => {
+	updateDisplayName: hooks.loginRequired((session, playlistId, displayName, cb) => {
 		async.waterfall([
 			(next) => {
-				db.models.playlist.updateOne({ _id: playlistId, createdBy: userId }, { $set: { displayName } }, {runValidators: true}, next);
+				db.models.playlist.updateOne({ _id: playlistId, createdBy: session.userId }, { $set: { displayName } }, {runValidators: true}, next);
 			},
 
 			(res, next) => {
@@ -405,11 +396,11 @@ let lib = {
 		], async (err, playlist) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("PLAYLIST_UPDATE_DISPLAY_NAME", `Updating display name to "${displayName}" for private playlist "${playlistId}" failed for user "${userId}". "${err}"`);
+				logger.error("PLAYLIST_UPDATE_DISPLAY_NAME", `Updating display name to "${displayName}" for private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`);
 				return cb({ status: 'failure', message: err});
 			}
-			logger.success("PLAYLIST_UPDATE_DISPLAY_NAME", `Successfully updated display name to "${displayName}" for private playlist "${playlistId}" for user "${userId}".`);
-			cache.pub('playlist.updateDisplayName', {playlistId: playlistId, displayName: displayName, userId: userId});
+			logger.success("PLAYLIST_UPDATE_DISPLAY_NAME", `Successfully updated display name to "${displayName}" for private playlist "${playlistId}" for user "${session.userId}".`);
+			cache.pub('playlist.updateDisplayName', {playlistId: playlistId, displayName: displayName, userId: session.userId});
 			return cb({ status: 'success', message: 'Playlist has been successfully updated' });
 		});
 	}),
@@ -421,16 +412,15 @@ let lib = {
 	 * @param {String} playlistId - the id of the playlist we are moving the song to the top from
 	 * @param {String} songId - the id of the song we are moving to the top of the list
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	moveSongToTop: hooks.loginRequired((session, playlistId, songId, cb, userId) => {
+	moveSongToTop: hooks.loginRequired((session, playlistId, songId, cb) => {
 		async.waterfall([
 			(next) => {
 				playlists.getPlaylist(playlistId, next);
 			},
 
 			(playlist, next) => {
-				if (!playlist || playlist.createdBy !== userId) return next('Playlist not found');
+				if (!playlist || playlist.createdBy !== session.userId) return next('Playlist not found');
 				async.each(playlist.songs, (song, next) => {
 					if (song.songId === songId) return next(song);
 					next();
@@ -464,11 +454,11 @@ let lib = {
 		], async (err, playlist) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("PLAYLIST_MOVE_SONG_TO_TOP", `Moving song "${songId}" to the top for private playlist "${playlistId}" failed for user "${userId}". "${err}"`);
+				logger.error("PLAYLIST_MOVE_SONG_TO_TOP", `Moving song "${songId}" to the top for private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`);
 				return cb({ status: 'failure', message: err});
 			}
-			logger.success("PLAYLIST_MOVE_SONG_TO_TOP", `Successfully moved song "${songId}" to the top for private playlist "${playlistId}" for user "${userId}".`);
-			cache.pub('playlist.moveSongToTop', {playlistId, songId, userId: userId});
+			logger.success("PLAYLIST_MOVE_SONG_TO_TOP", `Successfully moved song "${songId}" to the top for private playlist "${playlistId}" for user "${session.userId}".`);
+			cache.pub('playlist.moveSongToTop', {playlistId, songId, userId: session.userId});
 			return cb({ status: 'success', message: 'Playlist has been successfully updated' });
 		});
 	}),
@@ -480,16 +470,15 @@ let lib = {
 	 * @param {String} playlistId - the id of the playlist we are moving the song to the bottom from
 	 * @param {String} songId - the id of the song we are moving to the bottom of the list
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	moveSongToBottom: hooks.loginRequired((session, playlistId, songId, cb, userId) => {
+	moveSongToBottom: hooks.loginRequired((session, playlistId, songId, cb) => {
 		async.waterfall([
 			(next) => {
 				playlists.getPlaylist(playlistId, next);
 			},
 
 			(playlist, next) => {
-				if (!playlist || playlist.createdBy !== userId) return next('Playlist not found');
+				if (!playlist || playlist.createdBy !== session.userId) return next('Playlist not found');
 				async.each(playlist.songs, (song, next) => {
 					if (song.songId === songId) return next(song);
 					next();
@@ -520,11 +509,11 @@ let lib = {
 		], async (err, playlist) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("PLAYLIST_MOVE_SONG_TO_BOTTOM", `Moving song "${songId}" to the bottom for private playlist "${playlistId}" failed for user "${userId}". "${err}"`);
+				logger.error("PLAYLIST_MOVE_SONG_TO_BOTTOM", `Moving song "${songId}" to the bottom for private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`);
 				return cb({ status: 'failure', message: err});
 			}
-			logger.success("PLAYLIST_MOVE_SONG_TO_BOTTOM", `Successfully moved song "${songId}" to the bottom for private playlist "${playlistId}" for user "${userId}".`);
-			cache.pub('playlist.moveSongToBottom', {playlistId, songId, userId: userId});
+			logger.success("PLAYLIST_MOVE_SONG_TO_BOTTOM", `Successfully moved song "${songId}" to the bottom for private playlist "${playlistId}" for user "${session.userId}".`);
+			cache.pub('playlist.moveSongToBottom', {playlistId, songId, userId: session.userId});
 			return cb({ status: 'success', message: 'Playlist has been successfully updated' });
 		});
 	}),
@@ -535,9 +524,8 @@ let lib = {
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {String} playlistId - the id of the playlist we are moving the song to the top from
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	remove: hooks.loginRequired((session, playlistId, cb, userId) => {
+	remove: hooks.loginRequired((session, playlistId, cb) => {
 		async.waterfall([
 			(next) => {
 				playlists.deletePlaylist(playlistId, next);
@@ -545,11 +533,11 @@ let lib = {
 		], async (err) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("PLAYLIST_REMOVE", `Removing private playlist "${playlistId}" failed for user "${userId}". "${err}"`);
+				logger.error("PLAYLIST_REMOVE", `Removing private playlist "${playlistId}" failed for user "${session.userId}". "${err}"`);
 				return cb({ status: 'failure', message: err});
 			}
-			logger.success("PLAYLIST_REMOVE", `Successfully removed private playlist "${playlistId}" for user "${userId}".`);
-			cache.pub('playlist.delete', {userId: userId, playlistId});
+			logger.success("PLAYLIST_REMOVE", `Successfully removed private playlist "${playlistId}" for user "${session.userId}".`);
+			cache.pub('playlist.delete', {userId: session.userId, playlistId});
 			return cb({ status: 'success', message: 'Playlist successfully removed' });
 		});
 	})

+ 4 - 5
backend/logic/actions/punishments.js

@@ -52,9 +52,8 @@ module.exports = {
 	 * @param {String} reason - the reason for the ban
 	 * @param {String} expiresAt - the time the ban expires
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	banIP: hooks.adminRequired((session, value, reason, expiresAt, cb, userId) => {
+	banIP: hooks.adminRequired((session, value, reason, expiresAt, cb) => {
 		async.waterfall([
 			(next) => {
 				if (value === '') return next('You must provide an IP address to ban.');
@@ -101,15 +100,15 @@ module.exports = {
 			},
 
 			(next) => {
-				punishments.addPunishment('banUserIp', value, reason, expiresAt, userId, next)
+				punishments.addPunishment('banUserIp', value, reason, expiresAt, session.userId, next)
 			}
 		], async (err, punishment) => {
 			if (err && err !== true) {
 				err = await utils.getError(err);
-				logger.error("BAN_IP", `User ${userId} failed to ban IP address ${value} with the reason ${reason}. '${err}'`);
+				logger.error("BAN_IP", `User ${session.userId} failed to ban IP address ${value} with the reason ${reason}. '${err}'`);
 				cb({ status: 'failure', message: err });
 			}
-			logger.success("BAN_IP", `User ${userId} has successfully banned IP address ${value} with the reason ${reason}.`);
+			logger.success("BAN_IP", `User ${session.userId} has successfully banned IP address ${value} with the reason ${reason}.`);
 			cache.pub('ip.ban', { ip: value, punishment });
 			return cb({
 				status: 'success',

+ 13 - 17
backend/logic/actions/queueSongs.js

@@ -80,9 +80,8 @@ let lib = {
 	 * @param {String} songId - the id of the queuesong that gets updated
 	 * @param {Object} updatedSong - the object of the updated queueSong
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	update: hooks.adminRequired((session, songId, updatedSong, cb, userId) => {
+	update: hooks.adminRequired((session, songId, updatedSong, cb) => {
 		async.waterfall([
 			(next) => {
 				db.models.queueSong.findOne({_id: songId}, next);
@@ -99,11 +98,11 @@ let lib = {
 		], async (err) => {
 			if (err) {
 				err = await  utils.getError(err);
-				logger.error("QUEUE_UPDATE", `Updating queuesong "${songId}" failed for user ${userId}. "${err}"`);
+				logger.error("QUEUE_UPDATE", `Updating queuesong "${songId}" failed for user ${session.userId}. "${err}"`);
 				return cb({status: 'failure', message: err});
 			}
 			cache.pub('queue.update', songId);
-			logger.success("QUEUE_UPDATE", `User "${userId}" successfully update queuesong "${songId}".`);
+			logger.success("QUEUE_UPDATE", `User "${session.userId}" successfully update queuesong "${songId}".`);
 			return cb({status: 'success', message: 'Successfully updated song.'});
 		});
 	}),
@@ -114,7 +113,6 @@ let lib = {
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {String} songId - the id of the queuesong that gets removed
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
 	remove: hooks.adminRequired((session, songId, cb, userId) => {
 		async.waterfall([
@@ -124,11 +122,11 @@ let lib = {
 		], async (err) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("QUEUE_REMOVE", `Removing queuesong "${songId}" failed for user ${userId}. "${err}"`);
+				logger.error("QUEUE_REMOVE", `Removing queuesong "${songId}" failed for user ${session.userId}. "${err}"`);
 				return cb({status: 'failure', message: err});
 			}
 			cache.pub('queue.removedSong', songId);
-			logger.success("QUEUE_REMOVE", `User "${userId}" successfully removed queuesong "${songId}".`);
+			logger.success("QUEUE_REMOVE", `User "${session.userId}" successfully removed queuesong "${songId}".`);
 			return cb({status: 'success', message: 'Successfully updated song.'});
 		});
 	}),
@@ -139,9 +137,8 @@ let lib = {
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {String} songId - the id of the song that gets added
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	add: hooks.loginRequired((session, songId, cb, userId) => {
+	add: hooks.loginRequired((session, songId, cb) => {
 		let requestedAt = Date.now();
 
 		async.waterfall([
@@ -164,7 +161,7 @@ let lib = {
 					song.skipDuration = 0;
 					song.thumbnail = `${config.get("domain")}/assets/notes.png`;
 					song.explicit = false;
-					song.requestedBy = userId;
+					song.requestedBy = session.userId;
 					song.requestedAt = requestedAt;
 					next(null, song);
 				});
@@ -183,7 +180,7 @@ let lib = {
 				});
 			},
 			(newSong, next) => {
-				db.models.user.findOne({ _id: userId }, (err, user) => {
+				db.models.user.findOne({ _id: session.userId }, (err, user) => {
 					if (err) next(err, newSong);
 					else {
 						user.statistics.songsRequested = user.statistics.songsRequested + 1;
@@ -197,11 +194,11 @@ let lib = {
 		], async (err, newSong) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("QUEUE_ADD", `Adding queuesong "${songId}" failed for user ${userId}. "${err}"`);
+				logger.error("QUEUE_ADD", `Adding queuesong "${songId}" failed for user ${session.userId}. "${err}"`);
 				return cb({status: 'failure', message: err});
 			}
 			cache.pub('queue.newSong', newSong._id);
-			logger.success("QUEUE_ADD", `User "${userId}" successfully added queuesong "${songId}".`);
+			logger.success("QUEUE_ADD", `User "${session.userId}" successfully added queuesong "${songId}".`);
 			return cb({ status: 'success', message: 'Successfully added that song to the queue' });
 		});
 	}),
@@ -212,9 +209,8 @@ let lib = {
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {String} url - the url of the the YouTube playlist
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	addSetToQueue: hooks.loginRequired((session, url, cb, userId) => {
+	addSetToQueue: hooks.loginRequired((session, url, cb) => {
 		async.waterfall([
 			(next) => {
 				utils.getPlaylistFromYouTube(url, songs => {
@@ -236,10 +232,10 @@ let lib = {
 		], async (err) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("QUEUE_IMPORT", `Importing a YouTube playlist to the queue failed for user "${userId}". "${err}"`);
+				logger.error("QUEUE_IMPORT", `Importing a YouTube playlist to the queue failed for user "${session.userId}". "${err}"`);
 				return cb({ status: 'failure', message: err});
 			} else {
-				logger.success("QUEUE_IMPORT", `Successfully imported a YouTube playlist to the queue for user "${userId}".`);
+				logger.success("QUEUE_IMPORT", `Successfully imported a YouTube playlist to the queue for user "${session.userId}".`);
 				cb({ status: 'success', message: 'Playlist has been successfully imported.' });
 			}
 		});

+ 7 - 9
backend/logic/actions/reports.js

@@ -147,9 +147,8 @@ module.exports = {
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {String} reportId - the id of the report that is getting resolved
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	resolve: hooks.adminRequired((session, reportId, cb, userId) => {
+	resolve: hooks.adminRequired((session, reportId, cb) => {
 		async.waterfall([
 			(next) => {
 				db.models.report.findOne({ _id: reportId }).exec(next);
@@ -166,11 +165,11 @@ module.exports = {
 		], async (err) => {
 			if (err) {
 				err = await  utils.getError(err);
-				logger.error("REPORTS_RESOLVE", `Resolving report "${reportId}" failed by user "${userId}". "${err}"`);
+				logger.error("REPORTS_RESOLVE", `Resolving report "${reportId}" failed by user "${session.userId}". "${err}"`);
 				return cb({ 'status': 'failure', 'message': err});
 			} else {
 				cache.pub('report.resolve', reportId);
-				logger.success("REPORTS_RESOLVE", `User "${userId}" resolved report "${reportId}".`);
+				logger.success("REPORTS_RESOLVE", `User "${session.userId}" resolved report "${reportId}".`);
 				cb({ status: 'success', message: 'Successfully resolved Report' });
 			}
 		});
@@ -182,9 +181,8 @@ module.exports = {
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {Object} data - the object of the report data
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	create: hooks.loginRequired((session, data, cb, userId) => {
+	create: hooks.loginRequired((session, data, cb) => {
 		async.waterfall([
 
 			(next) => {
@@ -231,7 +229,7 @@ module.exports = {
 			},
 
 			(next) => {
-				data.createdBy = userId;
+				data.createdBy = session.userId;
 				data.createdAt = Date.now();
 				db.models.report.create(data, next);
 			}
@@ -239,11 +237,11 @@ module.exports = {
 		], async (err, report) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("REPORTS_CREATE", `Creating report for "${data.song._id}" failed by user "${userId}". "${err}"`);
+				logger.error("REPORTS_CREATE", `Creating report for "${data.song._id}" failed by user "${session.userId}". "${err}"`);
 				return cb({ 'status': 'failure', 'message': err });
 			} else {
 				cache.pub('report.create', report);
-				logger.success("REPORTS_CREATE", `User "${userId}" created report for "${data.songId}".`);
+				logger.success("REPORTS_CREATE", `User "${session.userId}" created report for "${data.songId}".`);
 				return cb({ 'status': 'success', 'message': 'Successfully created report' });
 			}
 		});

+ 23 - 29
backend/logic/actions/songs.js

@@ -203,9 +203,8 @@ module.exports = {
 	 * @param session
 	 * @param song - the song object
 	 * @param cb
-	 * @param userId
 	 */
-	add: hooks.adminRequired((session, song, cb, userId) => {
+	add: hooks.adminRequired((session, song, cb) => {
 		async.waterfall([
 			(next) => {
 				db.models.song.findOne({songId: song.songId}, next);
@@ -218,7 +217,7 @@ module.exports = {
 
 			(next) => {
 				const newSong = new db.models.song(song);
-				newSong.acceptedBy = userId;
+				newSong.acceptedBy = session.userId;
 				newSong.acceptedAt = Date.now();
 				newSong.save(next);
 			},
@@ -231,10 +230,10 @@ module.exports = {
 		], async (err) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("SONGS_ADD", `User "${userId}" failed to add song. "${err}"`);
+				logger.error("SONGS_ADD", `User "${session.userId}" failed to add song. "${err}"`);
 				return cb({'status': 'failure', 'message': err});
 			}
-			logger.success("SONGS_ADD", `User "${userId}" successfully added song "${song.songId}".`);
+			logger.success("SONGS_ADD", `User "${session.userId}" successfully added song "${song.songId}".`);
 			cache.pub('song.added', song.songId);
 			cb({status: 'success', message: 'Song has been moved from the queue successfully.'});
 		});
@@ -247,9 +246,8 @@ module.exports = {
 	 * @param session
 	 * @param songId - the song id
 	 * @param cb
-	 * @param userId
 	 */
-	like: hooks.loginRequired((session, songId, cb, userId) => {
+	like: hooks.loginRequired((session, songId, cb) => {
 		async.waterfall([
 			(next) => {
 				db.models.song.findOne({songId}, next);
@@ -262,14 +260,14 @@ module.exports = {
 		], async (err, song) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("SONGS_LIKE", `User "${userId}" failed to like song ${songId}. "${err}"`);
+				logger.error("SONGS_LIKE", `User "${session.userId}" failed to like song ${songId}. "${err}"`);
 				return cb({'status': 'failure', 'message': err});
 			}
 			let oldSongId = songId;
 			songId = song._id;
-			db.models.user.findOne({ _id: userId }, (err, user) => {
+			db.models.user.findOne({ _id: session.userId }, (err, user) => {
 				if (user.liked.indexOf(songId) !== -1) return cb({ status: 'failure', message: 'You have already liked this song.' });
-				db.models.user.updateOne({_id: userId}, {$push: {liked: songId}, $pull: {disliked: songId}}, err => {
+				db.models.user.updateOne({_id: session.userId}, {$push: {liked: songId}, $pull: {disliked: songId}}, err => {
 					if (!err) {
 						db.models.user.countDocuments({"liked": songId}, (err, likes) => {
 							if (err) return cb({ status: 'failure', message: 'Something went wrong while liking this song.' });
@@ -295,9 +293,8 @@ module.exports = {
 	 * @param session
 	 * @param songId - the song id
 	 * @param cb
-	 * @param userId
 	 */
-	dislike: hooks.loginRequired((session, songId, cb, userId) => {
+	dislike: hooks.loginRequired((session, songId, cb) => {
 		async.waterfall([
 			(next) => {
 				db.models.song.findOne({songId}, next);
@@ -310,14 +307,14 @@ module.exports = {
 		], async (err, song) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("SONGS_DISLIKE", `User "${userId}" failed to like song ${songId}. "${err}"`);
+				logger.error("SONGS_DISLIKE", `User "${session.userId}" failed to like song ${songId}. "${err}"`);
 				return cb({'status': 'failure', 'message': err});
 			}
 			let oldSongId = songId;
 			songId = song._id;
-			db.models.user.findOne({ _id: userId }, (err, user) => {
+			db.models.user.findOne({ _id: session.userId }, (err, user) => {
 				if (user.disliked.indexOf(songId) !== -1) return cb({ status: 'failure', message: 'You have already disliked this song.' });
-				db.models.user.updateOne({_id: userId}, {$push: {disliked: songId}, $pull: {liked: songId}}, err => {
+				db.models.user.updateOne({_id: session.userId}, {$push: {disliked: songId}, $pull: {liked: songId}}, err => {
 					if (!err) {
 						db.models.user.countDocuments({"liked": songId}, (err, likes) => {
 							if (err) return cb({ status: 'failure', message: 'Something went wrong while disliking this song.' });
@@ -343,9 +340,8 @@ module.exports = {
 	 * @param session
 	 * @param songId - the song id
 	 * @param cb
-	 * @param userId
 	 */
-	undislike: hooks.loginRequired((session, songId, cb, userId) => {
+	undislike: hooks.loginRequired((session, songId, cb) => {
 		async.waterfall([
 			(next) => {
 				db.models.song.findOne({songId}, next);
@@ -358,17 +354,17 @@ module.exports = {
 		], async (err, song) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("SONGS_UNDISLIKE", `User "${userId}" failed to like song ${songId}. "${err}"`);
+				logger.error("SONGS_UNDISLIKE", `User "${session.userId}" failed to like song ${songId}. "${err}"`);
 				return cb({'status': 'failure', 'message': err});
 			}
 			let oldSongId = songId;
 			songId = song._id;
-			db.models.user.findOne({_id: userId}, (err, user) => {
+			db.models.user.findOne({_id: session.userId}, (err, user) => {
 				if (user.disliked.indexOf(songId) === -1) return cb({
 					status: 'failure',
 					message: 'You have not disliked this song.'
 				});
-				db.models.user.updateOne({_id: userId}, {$pull: {liked: songId, disliked: songId}}, err => {
+				db.models.user.updateOne({_id: session.userId}, {$pull: {liked: songId, disliked: songId}}, err => {
 					if (!err) {
 						db.models.user.countDocuments({"liked": songId}, (err, likes) => {
 							if (err) return cb({
@@ -412,9 +408,8 @@ module.exports = {
 	 * @param session
 	 * @param songId - the song id
 	 * @param cb
-	 * @param userId
 	 */
-	unlike: hooks.loginRequired((session, songId, cb, userId) => {
+	unlike: hooks.loginRequired((session, songId, cb) => {
 		async.waterfall([
 			(next) => {
 				db.models.song.findOne({songId}, next);
@@ -427,14 +422,14 @@ module.exports = {
 		], async (err, song) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("SONGS_UNLIKE", `User "${userId}" failed to like song ${songId}. "${err}"`);
+				logger.error("SONGS_UNLIKE", `User "${session.userId}" failed to like song ${songId}. "${err}"`);
 				return cb({'status': 'failure', 'message': err});
 			}
 			let oldSongId = songId;
 			songId = song._id;
-			db.models.user.findOne({ _id: userId }, (err, user) => {
+			db.models.user.findOne({ _id: session.userId }, (err, user) => {
 				if (user.liked.indexOf(songId) === -1) return cb({ status: 'failure', message: 'You have not liked this song.' });
-				db.models.user.updateOne({_id: userId}, {$pull: {liked: songId, disliked: songId}}, err => {
+				db.models.user.updateOne({_id: session.userId}, {$pull: {liked: songId, disliked: songId}}, err => {
 					if (!err) {
 						db.models.user.countDocuments({"liked": songId}, (err, likes) => {
 							if (err) return cb({ status: 'failure', message: 'Something went wrong while unliking this song.' });
@@ -460,9 +455,8 @@ module.exports = {
 	 * @param session
 	 * @param songId - the song id
 	 * @param cb
-	 * @param userId
 	 */
-	getOwnSongRatings: hooks.loginRequired((session, songId, cb, userId) => {
+	getOwnSongRatings: hooks.loginRequired((session, songId, cb) => {
 		async.waterfall([
 			(next) => {
 				db.models.song.findOne({songId}, next);
@@ -475,11 +469,11 @@ module.exports = {
 		], async (err, song) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("SONGS_GET_OWN_RATINGS", `User "${userId}" failed to get ratings for ${songId}. "${err}"`);
+				logger.error("SONGS_GET_OWN_RATINGS", `User "${session.userId}" failed to get ratings for ${songId}. "${err}"`);
 				return cb({'status': 'failure', 'message': err});
 			}
 			let newSongId = song._id;
-			db.models.user.findOne({_id: userId}, (err, user) => {
+			db.models.user.findOne({_id: session.userId}, (err, user) => {
 				if (!err && user) {
 					return cb({
 						status: 'success',

+ 20 - 25
backend/logic/actions/stations.js

@@ -432,9 +432,8 @@ module.exports = {
 	 * @param session
 	 * @param stationId - the station id
 	 * @param cb
-	 * @param userId
 	 */
-	voteSkip: hooks.loginRequired((session, stationId, cb, userId) => {
+	voteSkip: hooks.loginRequired((session, stationId, cb) => {
 		async.waterfall([
 			(next) => {
 				stations.getStation(stationId, next);
@@ -442,7 +441,7 @@ module.exports = {
 
 			(station, next) => {
 				if (!station) return next('Station not found.');
-				stations.canUserViewStation(station, userId, (err, canView) => {
+				stations.canUserViewStation(station, session.userId, (err, canView) => {
 					if (err) return next(err);
 					if (canView) return next(null, station);
 					return next('Insufficient permissions.');
@@ -451,12 +450,12 @@ module.exports = {
 
 			(station, next) => {
 				if (!station.currentSong) return next('There is currently no song to skip.');
-				if (station.currentSong.skipVotes.indexOf(userId) !== -1) return next('You have already voted to skip this song.');
+				if (station.currentSong.skipVotes.indexOf(session.userId) !== -1) return next('You have already voted to skip this song.');
 				next(null, station);
 			},
 
 			(station, next) => {
-				db.models.station.updateOne({_id: stationId}, {$push: {"currentSong.skipVotes": userId}}, next)
+				db.models.station.updateOne({_id: stationId}, {$push: {"currentSong.skipVotes": session.userId}}, next)
 			},
 
 			(res, next) => {
@@ -849,9 +848,8 @@ module.exports = {
 	 * @param session
 	 * @param data - the station data
 	 * @param cb
-	 * @param userId
 	 */
-	create: hooks.loginRequired((session, data, cb, userId) => {
+	create: hooks.loginRequired((session, data, cb) => {
 		data.name = data.name.toLowerCase();
 		let blacklist = ["country", "edm", "musare", "hip-hop", "rap", "top-hits", "todays-hits", "old-school", "christmas", "about", "support", "staff", "help", "news", "terms", "privacy", "profile", "c", "community", "tos", "login", "register", "p", "official", "o", "trap", "faq", "team", "donate", "buy", "shop", "forums", "explore", "settings", "admin", "auth", "reset_password"];
 		async.waterfall([
@@ -868,7 +866,7 @@ module.exports = {
 				if (station) return next('A station with that name or display name already exists.');
 				const { name, displayName, description, genres, playlist, type, blacklistedGenres } = data;
 				if (type === 'official') {
-					db.models.user.findOne({_id: userId}, (err, user) => {
+					db.models.user.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.');
@@ -892,7 +890,7 @@ module.exports = {
 						description,
 						type,
 						privacy: 'private',
-						owner: userId,
+						owner: session.userId,
 						queue: [],
 						currentSong: null
 					}, next);
@@ -917,9 +915,8 @@ module.exports = {
 	 * @param stationId - the station id
 	 * @param songId - the song id
 	 * @param cb
-	 * @param userId
 	 */
-	addToQueue: hooks.loginRequired((session, stationId, songId, cb, userId) => {
+	addToQueue: hooks.loginRequired((session, stationId, songId, cb) => {
 		async.waterfall([
 			(next) => {
 				stations.getStation(stationId, next);
@@ -928,8 +925,8 @@ module.exports = {
 			(station, next) => {
 				if (!station) return next('Station not found.');
 				if (station.locked) {
-					db.models.user.findOne({ _id: userId }, (err, user) => {
-						if (user.role !== 'admin' && station.owner !== userId) return next('Only owners and admins can add songs to a locked queue.');
+					db.models.user.findOne({ _id: session.userId }, (err, user) => {
+						if (user.role !== 'admin' && station.owner !== session.userId) return next('Only owners and admins can add songs to a locked queue.');
 						else return next(null, station);
 					});
 				} else {
@@ -939,7 +936,7 @@ module.exports = {
 
 			(station, next) => {
 				if (station.type !== 'community') return next('That station is not a community station.');
-				stations.canUserViewStation(station, userId, (err, canView) => {
+				stations.canUserViewStation(station, session.userId, (err, canView) => {
 					if (err) return next(err);
 					if (canView) return next(null, station);
 					return next('Insufficient permissions.');
@@ -973,7 +970,7 @@ module.exports = {
 
 			(song, station, next) => {
 				let queue = station.queue;
-				song.requestedBy = userId;
+				song.requestedBy = session.userId;
 				queue.push(song);
 
 				let totalDuration = 0;
@@ -1042,9 +1039,8 @@ module.exports = {
 	 * @param stationId - the station id
 	 * @param songId - the song id
 	 * @param cb
-	 * @param userId
 	 */
-	removeFromQueue: hooks.ownerRequired((session, stationId, songId, cb, userId) => {
+	removeFromQueue: hooks.ownerRequired((session, stationId, songId, cb) => {
 		async.waterfall([
 			(next) => {
 				if (!songId) return next('Invalid song id.');
@@ -1126,9 +1122,8 @@ module.exports = {
 	 * @param stationId - the station id
 	 * @param playlistId - the private playlist id
 	 * @param cb
-	 * @param userId
 	 */
-	selectPrivatePlaylist: hooks.ownerRequired((session, stationId, playlistId, cb, userId) => {
+	selectPrivatePlaylist: hooks.ownerRequired((session, stationId, playlistId, cb) => {
 		async.waterfall([
 			(next) => {
 				stations.getStation(stationId, next);
@@ -1164,7 +1159,7 @@ module.exports = {
 		});
 	}),
 
-	favoriteStation: hooks.loginRequired((session, stationId, cb, userId) => {
+	favoriteStation: hooks.loginRequired((session, stationId, cb) => {
 		async.waterfall([
 			(next) => {
 				stations.getStation(stationId, next);
@@ -1180,7 +1175,7 @@ module.exports = {
 			},
 
 			(next) => {
-				db.models.user.updateOne({ _id: userId }, { $addToSet: { favoriteStations: stationId } }, next);
+				db.models.user.updateOne({ _id: session.userId }, { $addToSet: { favoriteStations: stationId } }, next);
 			},
 
 			(res, next) => {
@@ -1194,15 +1189,15 @@ module.exports = {
 				return cb({'status': 'failure', 'message': err});
 			}
 			logger.success("FAVORITE_STATION", `Favorited station "${stationId}" successfully.`);
-			cache.pub('user.favoritedStation', { userId, stationId });
+			cache.pub('user.favoritedStation', { userId: session.userId, stationId });
 			return cb({'status': 'success', 'message': 'Succesfully favorited station.'});
 		});
 	}),
 
-	unfavoriteStation: hooks.loginRequired((session, stationId, cb, userId) => {
+	unfavoriteStation: hooks.loginRequired((session, stationId, cb) => {
 		async.waterfall([
 			(next) => {
-				db.models.user.updateOne({ _id: userId }, { $pull: { favoriteStations: stationId } }, next);
+				db.models.user.updateOne({ _id: session.userId }, { $pull: { favoriteStations: stationId } }, next);
 			},
 
 			(res, next) => {
@@ -1216,7 +1211,7 @@ module.exports = {
 				return cb({'status': 'failure', 'message': err});
 			}
 			logger.success("UNFAVORITE_STATION", `Unfavorited station "${stationId}" successfully.`);
-			cache.pub('user.unfavoritedStation', { userId, stationId });
+			cache.pub('user.unfavoritedStation', { userId: session.userId, stationId });
 			return cb({'status': 'success', 'message': 'Succesfully unfavorited station.'});
 		});
 	}),

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

@@ -339,15 +339,15 @@ module.exports = {
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {String} userId - the id of the user we are trying to delete the sessions of
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} loggedInUser - the logged in userId automatically added by hooks
 	 */
-	removeSessions:  hooks.loginRequired((session, userId, cb, loggedInUser) => {
+	removeSessions:  hooks.loginRequired((session, userId, cb) => {
 
 		async.waterfall([
 
 			(next) => {
-				db.models.user.findOne({ _id: loggedInUser }, (err, user) => {
-					if (user.role !== 'admin' && loggedInUser !== userId) return next('Only admins and the owner of the account can remove their sessions.');
+				db.models.user.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.');
 					else return next();
 				});
 			},
@@ -522,13 +522,12 @@ module.exports = {
 	 * @param {String} updatingUserId - the updating user's id
 	 * @param {String} newUsername - the new username
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	updateUsername: hooks.loginRequired((session, updatingUserId, newUsername, cb, userId) => {
+	updateUsername: hooks.loginRequired((session, updatingUserId, newUsername, cb) => {
 		async.waterfall([
 			(next) => {
-				if (updatingUserId === userId) return next(null, true);
-				db.models.user.findOne({_id: userId}, next);
+				if (updatingUserId === session.userId) return next(null, true);
+				db.models.user.findOne({_id: session.userId}, next);
 			},
 
 			(user, next) => {
@@ -578,15 +577,14 @@ module.exports = {
 	 * @param {String} updatingUserId - the updating user's id
 	 * @param {String} newEmail - the new email
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	updateEmail: hooks.loginRequired(async (session, updatingUserId, newEmail, cb, userId) => {
+	updateEmail: hooks.loginRequired(async (session, updatingUserId, newEmail, cb) => {
 		newEmail = newEmail.toLowerCase();
 		let verificationToken = await utils.generateRandomString(64);
 		async.waterfall([
 			(next) => {
-				if (updatingUserId === userId) return next(null, true);
-				db.models.user.findOne({_id: userId}, next);
+				if (updatingUserId === session.userId) return next(null, true);
+				db.models.user.findOne({_id: session.userId}, next);
 			},
 
 			(user, next) => {
@@ -642,9 +640,8 @@ module.exports = {
 	 * @param {String} updatingUserId - the updating user's id
 	 * @param {String} newRole - the new role
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	updateRole: hooks.adminRequired((session, updatingUserId, newRole, cb, userId) => {
+	updateRole: hooks.adminRequired((session, updatingUserId, newRole, cb) => {
 		newRole = newRole.toLowerCase();
 		async.waterfall([
 
@@ -664,10 +661,10 @@ module.exports = {
 		], async (err) => {
 			if (err && err !== true) {
 				err = await utils.getError(err);
-				logger.error("UPDATE_ROLE", `User "${userId}" couldn't update role for user "${updatingUserId}" to role "${newRole}". "${err}"`);
+				logger.error("UPDATE_ROLE", `User "${session.userId}" couldn't update role for user "${updatingUserId}" to role "${newRole}". "${err}"`);
 				cb({status: 'failure', message: err});
 			} else {
-				logger.success("UPDATE_ROLE", `User "${userId}" updated the role of user "${updatingUserId}" to role "${newRole}".`);
+				logger.success("UPDATE_ROLE", `User "${session.userId}" updated the role of user "${updatingUserId}" to role "${newRole}".`);
 				cb({
 					status: 'success',
 					message: 'Role successfully updated.'
@@ -682,12 +679,11 @@ module.exports = {
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {String} newPassword - the new password
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	updatePassword: hooks.loginRequired((session, newPassword, cb, userId) => {
+	updatePassword: hooks.loginRequired((session, newPassword, cb) => {
 		async.waterfall([
 			(next) => {
-				db.models.user.findOne({_id: userId}, next);
+				db.models.user.findOne({_id: session.userId}, next);
 			},
 
 			(user, next) => {
@@ -710,16 +706,16 @@ module.exports = {
 			},
 
 			(hashedPassword, next) => {
-				db.models.user.updateOne({_id: userId}, {$set: {"services.password.password": hashedPassword}}, next);
+				db.models.user.updateOne({_id: session.userId}, {$set: {"services.password.password": hashedPassword}}, next);
 			}
 		], async (err) => {
 			if (err) {
 				err = await utils.getError(err);
-				logger.error("UPDATE_PASSWORD", `Failed updating user password of user '${userId}'. '${err}'.`);
+				logger.error("UPDATE_PASSWORD", `Failed updating user password of user '${session.userId}'. '${err}'.`);
 				return cb({ status: 'failure', message: err });
 			}
 
-			logger.success("UPDATE_PASSWORD", `User '${userId}' updated their password.`);
+			logger.success("UPDATE_PASSWORD", `User '${session.userId}' updated their password.`);
 			cb({
 				status: 'success',
 				message: 'Password successfully updated.'
@@ -733,13 +729,12 @@ module.exports = {
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {String} email - the email of the user that requests a password reset
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	requestPassword: hooks.loginRequired(async (session, cb, userId) => {
+	requestPassword: hooks.loginRequired(async (session, cb) => {
 		let code = await utils.generateRandomString(8);
 		async.waterfall([
 			(next) => {
-				db.models.user.findOne({_id: userId}, next);
+				db.models.user.findOne({_id: session.userId}, next);
 			},
 
 			(user, next) => {
@@ -760,10 +755,10 @@ module.exports = {
 		], async (err) => {
 			if (err && err !== true) {
 				err = await utils.getError(err);
-				logger.error("REQUEST_PASSWORD", `UserId '${userId}' failed to request password. '${err}'`);
+				logger.error("REQUEST_PASSWORD", `UserId '${session.userId}' failed to request password. '${err}'`);
 				cb({status: 'failure', message: err});
 			} else {
-				logger.success("REQUEST_PASSWORD", `UserId '${userId}' successfully requested a password.`);
+				logger.success("REQUEST_PASSWORD", `UserId '${session.userId}' successfully requested a password.`);
 				cb({
 					status: 'success',
 					message: 'Successfully requested password.'
@@ -778,13 +773,12 @@ module.exports = {
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {String} code - the password code
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	verifyPasswordCode: hooks.loginRequired((session, code, cb, userId) => {
+	verifyPasswordCode: hooks.loginRequired((session, code, cb) => {
 		async.waterfall([
 			(next) => {
 				if (!code || typeof code !== 'string') return next('Invalid code1.');
-				db.models.user.findOne({"services.password.set.code": code, _id: userId}, next);
+				db.models.user.findOne({"services.password.set.code": code, _id: session.userId}, next);
 			},
 
 			(user, next) => {
@@ -814,9 +808,8 @@ module.exports = {
 	 * @param {String} code - the password code
 	 * @param {String} newPassword - the new password code
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	changePasswordWithCode: hooks.loginRequired((session, code, newPassword, cb, userId) => {
+	changePasswordWithCode: hooks.loginRequired((session, code, newPassword, cb) => {
 		async.waterfall([
 			(next) => {
 				if (!code || typeof code !== 'string') return next('Invalid code1.');
@@ -853,7 +846,7 @@ module.exports = {
 				cb({status: 'failure', message: err});
 			} else {
 				logger.success("ADD_PASSWORD_WITH_CODE", `Code '${code}' successfully added password.`);
-				cache.pub('user.linkPassword', userId);
+				cache.pub('user.linkPassword', session.userId);
 				cb({
 					status: 'success',
 					message: 'Successfully added password.'
@@ -867,27 +860,26 @@ module.exports = {
 	 *
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	unlinkPassword: hooks.loginRequired((session, cb, userId) => {
+	unlinkPassword: hooks.loginRequired((session, cb) => {
 		async.waterfall([
 			(next) => {
-				db.models.user.findOne({_id: userId}, next);
+				db.models.user.findOne({_id: session.userId}, next);
 			},
 
 			(user, next) => {
 				if (!user) return next('Not logged in.');
 				if (!user.services.github || !user.services.github.id) return next('You can\'t remove password login without having GitHub login.');
-				db.models.user.updateOne({_id: userId}, {$unset: {"services.password": ''}}, next);
+				db.models.user.updateOne({_id: session.userId}, {$unset: {"services.password": ''}}, next);
 			}
 		], async (err) => {
 			if (err && err !== true) {
 				err = await utils.getError(err);
-				logger.error("UNLINK_PASSWORD", `Unlinking password failed for userId '${userId}'. '${err}'`);
+				logger.error("UNLINK_PASSWORD", `Unlinking password failed for userId '${session.userId}'. '${err}'`);
 				cb({status: 'failure', message: err});
 			} else {
-				logger.success("UNLINK_PASSWORD", `Unlinking password successful for userId '${userId}'.`);
-				cache.pub('user.unlinkPassword', userId);
+				logger.success("UNLINK_PASSWORD", `Unlinking password successful for userId '${session.userId}'.`);
+				cache.pub('user.unlinkPassword', session.userId);
 				cb({
 					status: 'success',
 					message: 'Successfully unlinked password.'
@@ -901,27 +893,26 @@ module.exports = {
 	 *
 	 * @param {Object} session - the session object automatically added by socket.io
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	unlinkGitHub: hooks.loginRequired((session, cb, userId) => {
+	unlinkGitHub: hooks.loginRequired((session, cb) => {
 		async.waterfall([
 			(next) => {
-				db.models.user.findOne({_id: userId}, next);
+				db.models.user.findOne({_id: session.userId}, next);
 			},
 
 			(user, next) => {
 				if (!user) return next('Not logged in.');
 				if (!user.services.password || !user.services.password.password) return next('You can\'t remove GitHub login without having password login.');
-				db.models.user.updateOne({_id: userId}, {$unset: {"services.github": ''}}, next);
+				db.models.user.updateOne({_id: session.userId}, {$unset: {"services.github": ''}}, next);
 			}
 		], async (err) => {
 			if (err && err !== true) {
 				err = await utils.getError(err);
-				logger.error("UNLINK_GITHUB", `Unlinking GitHub failed for userId '${userId}'. '${err}'`);
+				logger.error("UNLINK_GITHUB", `Unlinking GitHub failed for userId '${session.userId}'. '${err}'`);
 				cb({status: 'failure', message: err});
 			} else {
-				logger.success("UNLINK_GITHUB", `Unlinking GitHub successful for userId '${userId}'.`);
-				cache.pub('user.unlinkGitHub', userId);
+				logger.success("UNLINK_GITHUB", `Unlinking GitHub successful for userId '${session.userId}'.`);
+				cache.pub('user.unlinkGitHub', session.userId);
 				cb({
 					status: 'success',
 					message: 'Successfully unlinked GitHub.'
@@ -1071,9 +1062,8 @@ module.exports = {
 	 * @param {String} reason - the reason for the ban
 	 * @param {String} expiresAt - the time the ban expires
 	 * @param {Function} cb - gets called with the result
-	 * @param {String} userId - the userId automatically added by hooks
 	 */
-	banUserById: hooks.adminRequired((session, value, reason, expiresAt, cb, userId) => {
+	banUserById: hooks.adminRequired((session, value, reason, expiresAt, cb) => {
 		async.waterfall([
 			(next) => {
 				if (value === '') return next('You must provide an IP address to ban.');
@@ -1130,10 +1120,10 @@ module.exports = {
 		], async (err) => {
 			if (err && err !== true) {
 				err = await utils.getError(err);
-				logger.error("BAN_USER_BY_ID", `User ${userId} failed to ban user ${value} with the reason ${reason}. '${err}'`);
+				logger.error("BAN_USER_BY_ID", `User ${session.userId} failed to ban user ${value} with the reason ${reason}. '${err}'`);
 				cb({status: 'failure', message: err});
 			} else {
-				logger.success("BAN_USER_BY_ID", `User ${userId} has successfully banned user ${value} with the reason ${reason}.`);
+				logger.success("BAN_USER_BY_ID", `User ${session.userId} has successfully banned user ${value} with the reason ${reason}.`);
 				cb({
 					status: 'success',
 					message: 'Successfully banned user.'
@@ -1142,10 +1132,10 @@ module.exports = {
 		});
 	}),
 
-	getFavoriteStations: hooks.loginRequired((session, cb, userId) => {
+	getFavoriteStations: hooks.loginRequired((session, cb) => {
 		async.waterfall([
 			(next) => {
-				db.models.user.findOne({ _id: userId }, next);
+				db.models.user.findOne({ _id: session.userId }, next);
 			},
 
 			(user, next) => {
@@ -1155,10 +1145,10 @@ module.exports = {
 		], async (err, user) => {
 			if (err && err !== true) {
 				err = await utils.getError(err);
-				logger.error("GET_FAVORITE_STATIONS", `User ${userId} failed to get favorite stations. '${err}'`);
+				logger.error("GET_FAVORITE_STATIONS", `User ${session.userId} failed to get favorite stations. '${err}'`);
 				cb({status: 'failure', message: err});
 			} else {
-				logger.success("GET_FAVORITE_STATIONS", `User ${userId} got favorite stations.`);
+				logger.success("GET_FAVORITE_STATIONS", `User ${session.userId} got favorite stations.`);
 				cb({
 					status: 'success',
 					favoriteStations: user.favoriteStations