hasPermission.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. import async from "async";
  2. // eslint-disable-next-line
  3. import moduleManager from "../../index";
  4. const DBModule = moduleManager.modules.db;
  5. const CacheModule = moduleManager.modules.cache;
  6. const UtilsModule = moduleManager.modules.utils;
  7. const StationsModule = moduleManager.modules.stations;
  8. const permissions = {};
  9. permissions.dj = {
  10. "test.queue.add": true,
  11. "test.queue.remove": false,
  12. "stations.forceSkip": true,
  13. "stations.pause": true,
  14. "stations.resume": true,
  15. "stations.removeFromQueue": true,
  16. "stations.repositionSongInQueue": true,
  17. "stations.autofillPlaylist": true,
  18. "stations.removeAutofillPlaylist": true,
  19. "stations.blacklistPlaylist": true,
  20. "stations.removeBlacklistedPlaylist": 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. "punishments.getData": true,
  64. "punishments.getPunishmentsForUser": true,
  65. "punishments.findOne": true,
  66. "punishments.banIP": true,
  67. "reports.getData": true,
  68. "reports.findOne": true,
  69. "reports.getReportsForSong": true,
  70. "reports.resolve": true,
  71. "reports.toggleIssue": true,
  72. "stations.getData": true,
  73. "stations.resetQueue": true,
  74. "stations.remove": false,
  75. "youtube.getVideos": true,
  76. "youtube.requestSetAdmin": true
  77. };
  78. permissions.admin = {
  79. ...permissions.moderator,
  80. "test.remove.other": true,
  81. "songs.updateAll": true,
  82. "songs.remove": true,
  83. "songs.removeMany": true,
  84. "apis.joinAdminRoom.users": true,
  85. "apis.joinAdminRoom.statistics": true,
  86. "apis.joinAdminRoom.youtube": true,
  87. "dataRequests.getData": true,
  88. "dataRequests.resolve": true,
  89. "media.recalculateAllRatings": true,
  90. "media.removeImportJobs": true,
  91. "news.remove": true,
  92. "playlists.removeAdmin": true,
  93. "playlists.deleteOrphanedStationPlaylists": true,
  94. "playlists.deleteOrphanedGenrePlaylists": true,
  95. "playlists.requestOrphanedPlaylistSongs": true,
  96. "playlists.clearAndRefillStationPlaylist": true,
  97. "playlists.clearAndRefillGenrePlaylist": true,
  98. "playlists.clearAndRefillAllStationPlaylists": true,
  99. "playlists.clearAndRefillAllGenrePlaylists": true,
  100. "playlists.createMissingGenrePlaylists": true,
  101. "reports.remove": true,
  102. "stations.clearEveryStationQueue": true,
  103. "stations.remove": true,
  104. "users.getData": true,
  105. "users.adminRemove": true,
  106. "users.getUserFromId": true,
  107. "users.updateRole": true,
  108. "users.adminRequestPasswordReset": true,
  109. "users.resendVerifyEmail": true,
  110. "users.banUserById": true,
  111. "utils.getModules": true,
  112. "utils.getModule": true,
  113. "youtube.getQuotaStatus": true,
  114. "youtube.getQuotaChartData": true,
  115. "youtube.getApiRequests": true,
  116. "youtube.getApiRequest": true,
  117. "youtube.resetStoredApiRequests": true,
  118. "youtube.removeStoredApiRequest": true,
  119. "youtube.removeVideos": true
  120. };
  121. export const hasPermission = async (permission, session, stationId) => {
  122. const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
  123. return new Promise((resolve, reject) => {
  124. async.waterfall(
  125. [
  126. next => {
  127. let userId;
  128. if (typeof session === "object") {
  129. if (session.userId) userId = session.userId;
  130. else
  131. CacheModule.runJob(
  132. "HGET",
  133. {
  134. table: "sessions",
  135. key: session.sessionId
  136. },
  137. this
  138. )
  139. .then(_session => {
  140. if (_session && _session.userId) userId = _session.userId;
  141. })
  142. .catch(next);
  143. } else userId = session;
  144. if (!userId) return next("User ID required.");
  145. return userModel.findOne({ _id: userId }, next);
  146. },
  147. (user, next) => {
  148. if (!user) return next("Login required.");
  149. if (!stationId) return next(null, [user.role]);
  150. return StationsModule.runJob("GET_STATION", { stationId }, this)
  151. .then(station => {
  152. if (!station) return next("Station not found.");
  153. if (station.type === "community" && station.owner === user._id)
  154. return next(null, [user.role, "owner"]);
  155. // if (station.type === "community" && station.djs.find(userId))
  156. // return next(null, [user.role, "dj"]);
  157. if (user.role === "admin" || user.role === "moderator") return next(null, [user.role]);
  158. return next("Invalid permissions.");
  159. })
  160. .catch(next);
  161. },
  162. (roles, next) => {
  163. if (!roles) return next("Role required.");
  164. let permissionFound;
  165. roles.forEach(role => {
  166. if (permissions[role] && permissions[role][permission]) permissionFound = true;
  167. });
  168. if (permissionFound) return next();
  169. return next("Insufficient permissions.");
  170. }
  171. ],
  172. async err => {
  173. if (err) {
  174. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  175. // TODO
  176. // this.log(
  177. // "INFO",
  178. // "HAS_PERMISSION",
  179. // `User "${userId}" does not have required permission "${permission}". "${err}"`
  180. // );
  181. return reject(err);
  182. }
  183. // TODO
  184. // this.log("INFO", "HAS_PERMISSION", `User "${userId}" has required permission "${permission}".`, false);
  185. return resolve();
  186. }
  187. );
  188. });
  189. };
  190. export const useHasPermission = (options, destination) =>
  191. async function useHasPermission(session, ...args) {
  192. const permission = typeof options === "object" ? options.permission : options;
  193. const stationId = typeof options === "object" ? options.stationId : null;
  194. const cb = args[args.length - 1];
  195. async.waterfall(
  196. [
  197. next => {
  198. if (!session || !session.sessionId) return next("Login required.");
  199. return hasPermission(permission, session, stationId)
  200. .then(() => next())
  201. .catch(next);
  202. }
  203. ],
  204. async err => {
  205. if (err) {
  206. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  207. this.log(
  208. "INFO",
  209. "USE_HAS_PERMISSION",
  210. `User "${session.userId}" does not have required permission "${permission}". "${err}"`
  211. );
  212. return cb({ status: "error", message: err });
  213. }
  214. this.log(
  215. "INFO",
  216. "USE_HAS_PERMISSION",
  217. `User "${session.userId}" has required permission "${permission}".`,
  218. false
  219. );
  220. return destination.apply(this, [session].concat(args));
  221. }
  222. );
  223. };