hasPermission.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. import async from "async";
  2. // eslint-disable-next-line
  3. import moduleManager from "../../index";
  4. const permissions = {};
  5. permissions.dj = {
  6. "test.queue.add": true,
  7. "test.queue.remove": false,
  8. "stations.view": true,
  9. "stations.skip": true,
  10. "stations.pause": true,
  11. "stations.resume": true,
  12. "stations.addToQueue": true,
  13. "stations.removeFromQueue": true,
  14. "stations.repositionSongInQueue": true,
  15. "stations.autofillPlaylist": true,
  16. "stations.removeAutofillPlaylist": true,
  17. "stations.blacklistPlaylist": true,
  18. "stations.removeBlacklistedPlaylist": true,
  19. "stations.index": true,
  20. "stations.getPlaylist": true
  21. };
  22. permissions.owner = {
  23. ...permissions.dj,
  24. "test.queue.remove": true,
  25. "stations.update": true,
  26. "stations.remove": true
  27. };
  28. permissions.moderator = {
  29. ...permissions.owner,
  30. "test.remove.other": false,
  31. "songs.length": true,
  32. "songs.getData": true,
  33. "songs.getSongFromId": true,
  34. "songs.getSongsFromYoutubeIds": true,
  35. "songs.create": true,
  36. "songs.update": true,
  37. "songs.verify": true,
  38. "songs.verifyMany": true,
  39. "songs.unverify": true,
  40. "songs.unverifyMany": true,
  41. "songs.getGenres": true,
  42. "songs.editGenres": true,
  43. "songs.getArtists": true,
  44. "songs.editArtists": true,
  45. "songs.getTags": true,
  46. "songs.editTags": true,
  47. "apis.searchDiscogs": true,
  48. "apis.joinAdminRoom.songs": true,
  49. "apis.joinAdminRoom.stations": true,
  50. "apis.joinAdminRoom.reports": true,
  51. "apis.joinAdminRoom.news": true,
  52. "apis.joinAdminRoom.playlists": true,
  53. "apis.joinAdminRoom.punishments": true,
  54. "apis.joinAdminRoom.youtubeVideos": true,
  55. "apis.joinAdminRoom.import": true,
  56. "media.getImportJobs": true,
  57. "news.getData": true,
  58. "news.create": true,
  59. "news.update": true,
  60. "playlists.getData": true,
  61. "playlists.searchOfficial": true,
  62. "playlists.updatePrivacyAdmin": true,
  63. "playlists.getPlaylist": true,
  64. "playlists.repositionSong": true,
  65. "playlists.addSongToPlaylist": true,
  66. "playlists.addSetToPlaylist": true,
  67. "playlists.removeSongFromPlaylist": true,
  68. "punishments.getData": true,
  69. "punishments.getPunishmentsForUser": true,
  70. "punishments.findOne": true,
  71. "punishments.banIP": true,
  72. "reports.getData": true,
  73. "reports.findOne": true,
  74. "reports.getReportsForSong": true,
  75. "reports.resolve": true,
  76. "reports.toggleIssue": true,
  77. "stations.getData": true,
  78. "stations.resetQueue": true,
  79. "stations.remove": false,
  80. "stations.index": false,
  81. "stations.index.other": true,
  82. "stations.create.official": true,
  83. "youtube.getVideos": true,
  84. "youtube.requestSetAdmin": true
  85. };
  86. permissions.admin = {
  87. ...permissions.moderator,
  88. "test.remove.other": true,
  89. "songs.updateAll": true,
  90. "songs.remove": true,
  91. "songs.removeMany": true,
  92. "apis.joinAdminRoom.users": true,
  93. "apis.joinAdminRoom.statistics": true,
  94. "apis.joinAdminRoom.youtube": true,
  95. "dataRequests.getData": true,
  96. "dataRequests.resolve": true,
  97. "media.recalculateAllRatings": true,
  98. "media.removeImportJobs": true,
  99. "news.remove": true,
  100. "playlists.removeAdmin": true,
  101. "playlists.deleteOrphanedStationPlaylists": true,
  102. "playlists.deleteOrphanedGenrePlaylists": true,
  103. "playlists.requestOrphanedPlaylistSongs": true,
  104. "playlists.clearAndRefillStationPlaylist": true,
  105. "playlists.clearAndRefillGenrePlaylist": true,
  106. "playlists.clearAndRefillAllStationPlaylists": true,
  107. "playlists.clearAndRefillAllGenrePlaylists": true,
  108. "playlists.createMissingGenrePlaylists": true,
  109. "reports.remove": true,
  110. "stations.clearEveryStationQueue": true,
  111. "stations.remove": true,
  112. "users.getData": true,
  113. "users.adminRemove": true,
  114. "users.getUserFromId": true,
  115. "users.updateRole": true,
  116. "users.adminRequestPasswordReset": true,
  117. "users.resendVerifyEmail": true,
  118. "users.banUserById": true,
  119. "users.removeSessions": true,
  120. "users.updateUsername": true,
  121. "users.updateEmail": true,
  122. "users.updateName": true,
  123. "users.updateLocation": true,
  124. "users.updateBio": true,
  125. "users.updateAvatar": true,
  126. "utils.getModules": true,
  127. "utils.getModule": true,
  128. "youtube.getQuotaStatus": true,
  129. "youtube.getQuotaChartData": true,
  130. "youtube.getApiRequests": true,
  131. "youtube.getApiRequest": true,
  132. "youtube.resetStoredApiRequests": true,
  133. "youtube.removeStoredApiRequest": true,
  134. "youtube.removeVideos": true
  135. };
  136. export const hasPermission = async (permission, session, stationId) => {
  137. const CacheModule = moduleManager.modules.cache;
  138. const DBModule = moduleManager.modules.db;
  139. const StationsModule = moduleManager.modules.stations;
  140. const UtilsModule = moduleManager.modules.utils;
  141. const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
  142. return new Promise((resolve, reject) => {
  143. async.waterfall(
  144. [
  145. next => {
  146. let userId;
  147. if (typeof session === "object") {
  148. if (session.userId) userId = session.userId;
  149. else
  150. CacheModule.runJob(
  151. "HGET",
  152. {
  153. table: "sessions",
  154. key: session.sessionId
  155. },
  156. this
  157. )
  158. .then(_session => {
  159. if (_session && _session.userId) userId = _session.userId;
  160. })
  161. .catch(next);
  162. } else userId = session;
  163. if (!userId) return next("User ID required.");
  164. return userModel.findOne({ _id: userId }, next);
  165. },
  166. (user, next) => {
  167. if (!user) return next("Login required.");
  168. if (!stationId) return next(null, [user.role]);
  169. return StationsModule.runJob("GET_STATION", { stationId }, this)
  170. .then(station => {
  171. if (!station) return next("Station not found.");
  172. if (station.type === "community" && station.owner === user._id.toString())
  173. return next(null, [user.role, "owner"]);
  174. // if (station.type === "community" && station.djs.find(userId))
  175. // return next(null, [user.role, "dj"]);
  176. if (user.role === "admin" || user.role === "moderator") return next(null, [user.role]);
  177. return next("Invalid permissions.");
  178. })
  179. .catch(next);
  180. },
  181. (roles, next) => {
  182. if (!roles) return next("Role required.");
  183. let permissionFound;
  184. roles.forEach(role => {
  185. if (permissions[role] && permissions[role][permission]) permissionFound = true;
  186. });
  187. if (permissionFound) return next();
  188. return next("Insufficient permissions.");
  189. }
  190. ],
  191. async err => {
  192. const userId = typeof session === "object" ? session.userId || session.sessionId : session;
  193. if (err) {
  194. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  195. UtilsModule.log(
  196. "INFO",
  197. "HAS_PERMISSION",
  198. `User "${userId}" does not have required permission "${permission}". "${err}"`
  199. );
  200. return reject(err);
  201. }
  202. UtilsModule.log(
  203. "INFO",
  204. "HAS_PERMISSION",
  205. `User "${userId}" has required permission "${permission}".`,
  206. false
  207. );
  208. return resolve();
  209. }
  210. );
  211. });
  212. };
  213. export const useHasPermission = (options, destination) =>
  214. async function useHasPermission(session, ...args) {
  215. const UtilsModule = moduleManager.modules.utils;
  216. const permission = typeof options === "object" ? options.permission : options;
  217. const stationId = typeof options === "object" ? options.stationId : null;
  218. const cb = args[args.length - 1];
  219. async.waterfall(
  220. [
  221. next => {
  222. if (!session || !session.sessionId) return next("Login required.");
  223. return hasPermission(permission, session, stationId)
  224. .then(() => next())
  225. .catch(next);
  226. }
  227. ],
  228. async err => {
  229. if (err) {
  230. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  231. this.log(
  232. "INFO",
  233. "USE_HAS_PERMISSION",
  234. `User "${session.userId}" does not have required permission "${permission}". "${err}"`
  235. );
  236. return cb({ status: "error", message: err });
  237. }
  238. this.log(
  239. "INFO",
  240. "USE_HAS_PERMISSION",
  241. `User "${session.userId}" has required permission "${permission}".`,
  242. false
  243. );
  244. return destination.apply(this, [session].concat(args));
  245. }
  246. );
  247. };