hasPermission.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. import async from "async";
  2. // eslint-disable-next-line
  3. import moduleManager from "../../index";
  4. const permissions = {};
  5. permissions.dj = {
  6. "stations.autofill": true,
  7. "stations.blacklist": true,
  8. "stations.index": true,
  9. "stations.playback.toggle": true,
  10. "stations.queue.remove": true,
  11. "stations.queue.reposition": true,
  12. "stations.queue.reset": true,
  13. "stations.request": true,
  14. "stations.skip": true,
  15. "stations.view": true,
  16. "stations.view.manage": true
  17. };
  18. permissions.owner = {
  19. ...permissions.dj,
  20. "stations.remove": true,
  21. "stations.update": true
  22. };
  23. permissions.moderator = {
  24. ...permissions.owner,
  25. "admin.view": true,
  26. "admin.view.import": true,
  27. "admin.view.news": true,
  28. "admin.view.playlists": true,
  29. "admin.view.punishments": true,
  30. "admin.view.reports": true,
  31. "admin.view.songs": true,
  32. "admin.view.stations": true,
  33. "admin.view.users": true,
  34. "admin.view.youtubeVideos": true,
  35. "apis.searchDiscogs": true,
  36. "news.create": true,
  37. "news.update": true,
  38. "playlists.get": true,
  39. "playlists.update.displayName": false,
  40. "playlists.update.privacy": true,
  41. "playlists.songs.add": true,
  42. "playlists.songs.remove": true,
  43. "playlists.songs.reposition": true,
  44. "playlists.view.others": true,
  45. "punishments.banIP": true,
  46. "punishments.get": true,
  47. "reports.get": true,
  48. "reports.update": true,
  49. "songs.create": true,
  50. "songs.get": true,
  51. "songs.update": true,
  52. "songs.verify": true,
  53. "stations.create.official": true,
  54. "stations.index": false,
  55. "stations.index.other": true,
  56. "stations.remove": false,
  57. "users.get": true,
  58. "users.ban": true,
  59. "users.requestPasswordReset": true,
  60. "users.resendVerifyEmail": true,
  61. "users.update": true,
  62. "youtube.requestSetAdmin": true
  63. };
  64. permissions.admin = {
  65. ...permissions.moderator,
  66. "admin.view.dataRequests": true,
  67. "admin.view.statistics": true,
  68. "admin.view.youtube": true,
  69. "dataRequests.resolve": true,
  70. "media.recalculateAllRatings": true,
  71. "media.removeImportJobs": true,
  72. "news.remove": true,
  73. "playlists.clearAndRefill": true,
  74. "playlists.clearAndRefillAll": true,
  75. "playlists.createMissing": true,
  76. "playlists.deleteOrphaned": true,
  77. "playlists.removeAdmin": true,
  78. "playlists.requestOrphanedPlaylistSongs": true,
  79. "punishments.deactivate": true,
  80. "reports.remove": true,
  81. "songs.remove": true,
  82. "songs.updateAll": true,
  83. "stations.clearEveryStationQueue": true,
  84. "stations.remove": true,
  85. "users.remove": true,
  86. "users.remove.sessions": true,
  87. "users.update.restricted": true,
  88. "utils.getModules": true,
  89. "youtube.getApiRequest": true,
  90. "youtube.resetStoredApiRequests": true,
  91. "youtube.removeStoredApiRequest": true,
  92. "youtube.removeVideos": true
  93. };
  94. export const hasPermission = async (permission, session, stationId) => {
  95. const CacheModule = moduleManager.modules.cache;
  96. const DBModule = moduleManager.modules.db;
  97. const StationsModule = moduleManager.modules.stations;
  98. const UtilsModule = moduleManager.modules.utils;
  99. const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
  100. return new Promise((resolve, reject) => {
  101. async.waterfall(
  102. [
  103. next => {
  104. let userId;
  105. if (typeof session === "object") {
  106. if (session.userId) userId = session.userId;
  107. else
  108. CacheModule.runJob(
  109. "HGET",
  110. {
  111. table: "sessions",
  112. key: session.sessionId
  113. },
  114. this
  115. )
  116. .then(_session => {
  117. if (_session && _session.userId) userId = _session.userId;
  118. })
  119. .catch(next);
  120. } else userId = session;
  121. if (!userId) return next("User ID required.");
  122. return userModel.findOne({ _id: userId }, next);
  123. },
  124. (user, next) => {
  125. if (!user) return next("Login required.");
  126. if (!stationId) return next(null, [user.role]);
  127. return StationsModule.runJob("GET_STATION", { stationId }, this)
  128. .then(station => {
  129. if (!station) return next("Station not found.");
  130. if (station.type === "community" && station.owner === user._id.toString())
  131. return next(null, [user.role, "owner"]);
  132. // if (station.type === "community" && station.djs.find(userId))
  133. // return next(null, [user.role, "dj"]);
  134. if (user.role === "admin" || user.role === "moderator") return next(null, [user.role]);
  135. return next("Invalid permissions.");
  136. })
  137. .catch(next);
  138. },
  139. (roles, next) => {
  140. if (!roles) return next("Role required.");
  141. let permissionFound;
  142. roles.forEach(role => {
  143. if (permissions[role] && permissions[role][permission]) permissionFound = true;
  144. });
  145. if (permissionFound) return next();
  146. return next("Insufficient permissions.");
  147. }
  148. ],
  149. async err => {
  150. const userId = typeof session === "object" ? session.userId || session.sessionId : session;
  151. if (err) {
  152. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  153. UtilsModule.log(
  154. "INFO",
  155. "HAS_PERMISSION",
  156. `User "${userId}" does not have required permission "${permission}". "${err}"`
  157. );
  158. return reject(err);
  159. }
  160. UtilsModule.log(
  161. "INFO",
  162. "HAS_PERMISSION",
  163. `User "${userId}" has required permission "${permission}".`,
  164. false
  165. );
  166. return resolve();
  167. }
  168. );
  169. });
  170. };
  171. export const useHasPermission = (options, destination) =>
  172. async function useHasPermission(session, ...args) {
  173. const UtilsModule = moduleManager.modules.utils;
  174. const permission = typeof options === "object" ? options.permission : options;
  175. const stationId = typeof options === "object" ? options.stationId : null;
  176. const cb = args[args.length - 1];
  177. async.waterfall(
  178. [
  179. next => {
  180. if (!session || !session.sessionId) return next("Login required.");
  181. return hasPermission(permission, session, stationId)
  182. .then(() => next())
  183. .catch(next);
  184. }
  185. ],
  186. async err => {
  187. if (err) {
  188. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  189. this.log(
  190. "INFO",
  191. "USE_HAS_PERMISSION",
  192. `User "${session.userId}" does not have required permission "${permission}". "${err}"`
  193. );
  194. return cb({ status: "error", message: err });
  195. }
  196. this.log(
  197. "INFO",
  198. "USE_HAS_PERMISSION",
  199. `User "${session.userId}" has required permission "${permission}".`,
  200. false
  201. );
  202. return destination.apply(this, [session].concat(args));
  203. }
  204. );
  205. };
  206. export const getUserPermissions = async (session, stationId) => {
  207. const CacheModule = moduleManager.modules.cache;
  208. const DBModule = moduleManager.modules.db;
  209. const StationsModule = moduleManager.modules.stations;
  210. const UtilsModule = moduleManager.modules.utils;
  211. const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
  212. return new Promise((resolve, reject) => {
  213. async.waterfall(
  214. [
  215. next => {
  216. let userId;
  217. if (typeof session === "object") {
  218. if (session.userId) userId = session.userId;
  219. else
  220. CacheModule.runJob(
  221. "HGET",
  222. {
  223. table: "sessions",
  224. key: session.sessionId
  225. },
  226. this
  227. )
  228. .then(_session => {
  229. if (_session && _session.userId) userId = _session.userId;
  230. })
  231. .catch(next);
  232. } else userId = session;
  233. if (!userId) return next("User ID required.");
  234. return userModel.findOne({ _id: userId }, next);
  235. },
  236. (user, next) => {
  237. if (!user) return next("Login required.");
  238. if (!stationId) return next(null, [user.role]);
  239. return StationsModule.runJob("GET_STATION", { stationId }, this)
  240. .then(station => {
  241. if (!station) return next("Station not found.");
  242. if (station.type === "community" && station.owner === user._id.toString())
  243. return next(null, [user.role, "owner"]);
  244. // if (station.type === "community" && station.djs.find(userId))
  245. // return next(null, [user.role, "dj"]);
  246. if (user.role === "admin" || user.role === "moderator") return next(null, [user.role]);
  247. return next("Invalid permissions.");
  248. })
  249. .catch(next);
  250. },
  251. (roles, next) => {
  252. if (!roles) return next("Role required.");
  253. let rolePermissions = {};
  254. roles.forEach(role => {
  255. if (permissions[role]) rolePermissions = { ...rolePermissions, ...permissions[role] };
  256. });
  257. return next(null, rolePermissions);
  258. }
  259. ],
  260. async (err, rolePermissions) => {
  261. const userId = typeof session === "object" ? session.userId || session.sessionId : session;
  262. if (err) {
  263. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  264. UtilsModule.log(
  265. "INFO",
  266. "GET_USER_PERMISSIONS",
  267. `Failed to get permissions for user "${userId}". "${err}"`
  268. );
  269. return reject(err);
  270. }
  271. UtilsModule.log("INFO", "GET_USER_PERMISSIONS", `Fetched permissions for user "${userId}".`, false);
  272. return resolve(rolePermissions);
  273. }
  274. );
  275. });
  276. };