punishments.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. import async from "async";
  2. import { isAdminRequired } from "./hooks";
  3. import moduleManager from "../../index";
  4. const DBModule = moduleManager.modules.db;
  5. const UtilsModule = moduleManager.modules.utils;
  6. const WSModule = moduleManager.modules.ws;
  7. const CacheModule = moduleManager.modules.cache;
  8. const PunishmentsModule = moduleManager.modules.punishments;
  9. CacheModule.runJob("SUB", {
  10. channel: "ip.ban",
  11. cb: data => {
  12. WSModule.runJob("EMIT_TO_ROOM", {
  13. room: "admin.punishments",
  14. args: ["event:admin.punishment.created", { data: { punishment: data.punishment } }]
  15. });
  16. WSModule.runJob("SOCKETS_FROM_IP", { ip: data.ip }, this).then(sockets => {
  17. sockets.forEach(socket => {
  18. socket.disconnect(true);
  19. });
  20. });
  21. }
  22. });
  23. export default {
  24. /**
  25. * Gets punishments, used in the admin punishments page by the AdvancedTable component
  26. *
  27. * @param {object} session - the session object automatically added by the websocket
  28. * @param page - the page
  29. * @param pageSize - the size per page
  30. * @param properties - the properties to return for each punishment
  31. * @param sort - the sort object
  32. * @param queries - the queries array
  33. * @param operator - the operator for queries
  34. * @param cb
  35. */
  36. getData: isAdminRequired(async function getSet(session, page, pageSize, properties, sort, queries, operator, cb) {
  37. async.waterfall(
  38. [
  39. next => {
  40. DBModule.runJob(
  41. "GET_DATA",
  42. {
  43. page,
  44. pageSize,
  45. properties,
  46. sort,
  47. queries,
  48. operator,
  49. modelName: "punishment",
  50. blacklistedProperties: [],
  51. specialProperties: {
  52. status: [
  53. {
  54. $addFields: {
  55. status: {
  56. $cond: [
  57. { $eq: ["$active", true] },
  58. {
  59. $cond: [
  60. { $gt: [new Date(), "$expiresAt"] },
  61. "Inactive",
  62. "Active"
  63. ]
  64. },
  65. "Inactive"
  66. ]
  67. }
  68. }
  69. }
  70. ],
  71. value: [
  72. {
  73. $addFields: {
  74. valueOID: {
  75. $convert: {
  76. input: "$value",
  77. to: "objectId",
  78. onError: "unknown",
  79. onNull: "unknown"
  80. }
  81. }
  82. }
  83. },
  84. {
  85. $lookup: {
  86. from: "users",
  87. localField: "valueOID",
  88. foreignField: "_id",
  89. as: "valueUser"
  90. }
  91. },
  92. {
  93. $unwind: {
  94. path: "$valueUser",
  95. preserveNullAndEmptyArrays: true
  96. }
  97. },
  98. {
  99. $addFields: {
  100. valueUsername: {
  101. $cond: [
  102. { $eq: ["$type", "banUserId"] },
  103. { $ifNull: ["$valueUser.username", "unknown"] },
  104. null
  105. ]
  106. }
  107. }
  108. },
  109. {
  110. $project: {
  111. valueOID: 0,
  112. valueUser: 0
  113. }
  114. }
  115. ],
  116. punishedBy: [
  117. {
  118. $addFields: {
  119. punishedByOID: {
  120. $convert: {
  121. input: "$punishedBy",
  122. to: "objectId",
  123. onError: "unknown",
  124. onNull: "unknown"
  125. }
  126. }
  127. }
  128. },
  129. {
  130. $lookup: {
  131. from: "users",
  132. localField: "punishedByOID",
  133. foreignField: "_id",
  134. as: "punishedByUser"
  135. }
  136. },
  137. {
  138. $unwind: {
  139. path: "$punishedByUser",
  140. preserveNullAndEmptyArrays: true
  141. }
  142. },
  143. {
  144. $addFields: {
  145. punishedByUsername: {
  146. $ifNull: ["$punishedByUser.username", "unknown"]
  147. }
  148. }
  149. },
  150. {
  151. $project: {
  152. punishedByOID: 0,
  153. punishedByUser: 0
  154. }
  155. }
  156. ]
  157. },
  158. specialQueries: {
  159. value: newQuery => ({ $or: [newQuery, { valueUsername: newQuery.value }] }),
  160. punishedBy: newQuery => ({
  161. $or: [newQuery, { punishedByUsername: newQuery.punishedBy }]
  162. })
  163. }
  164. },
  165. this
  166. )
  167. .then(response => {
  168. next(null, response);
  169. })
  170. .catch(err => {
  171. next(err);
  172. });
  173. }
  174. ],
  175. async (err, response) => {
  176. if (err && err !== true) {
  177. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  178. this.log("ERROR", "PUNISHMENTS_GET_DATA", `Failed to get data from punishments. "${err}"`);
  179. return cb({ status: "error", message: err });
  180. }
  181. this.log("SUCCESS", "PUNISHMENTS_GET_DATA", `Got data from punishments successfully.`);
  182. return cb({
  183. status: "success",
  184. message: "Successfully got data from punishments.",
  185. data: response
  186. });
  187. }
  188. );
  189. }),
  190. /**
  191. * Gets all punishments for a user
  192. *
  193. * @param {object} session - the session object automatically added by the websocket
  194. * @param {string} userId - the id of the user
  195. * @param {Function} cb - gets called with the result
  196. */
  197. getPunishmentsForUser: isAdminRequired(async function getPunishmentsForUser(session, userId, cb) {
  198. const punishmentModel = await DBModule.runJob("GET_MODEL", { modelName: "punishment" }, this);
  199. punishmentModel.find({ type: "banUserId", value: userId }, async (err, punishments) => {
  200. if (err) {
  201. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  202. this.log(
  203. "ERROR",
  204. "GET_PUNISHMENTS_FOR_USER",
  205. `Getting punishments for user ${userId} failed. "${err}"`
  206. );
  207. return cb({ status: "error", message: err });
  208. }
  209. this.log("SUCCESS", "GET_PUNISHMENTS_FOR_USER", `Got punishments for user ${userId} successful.`);
  210. return cb({ status: "success", data: { punishments } });
  211. });
  212. }),
  213. /**
  214. * Returns a punishment by id
  215. *
  216. * @param {object} session - the session object automatically added by the websocket
  217. * @param {string} punishmentId - the punishment id
  218. * @param {Function} cb - gets called with the result
  219. */
  220. findOne: isAdminRequired(async function findOne(session, punishmentId, cb) {
  221. const punishmentModel = await DBModule.runJob("GET_MODEL", { modelName: "punishment" }, this);
  222. async.waterfall([next => punishmentModel.findOne({ _id: punishmentId }, next)], async (err, punishment) => {
  223. if (err) {
  224. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  225. this.log(
  226. "ERROR",
  227. "GET_PUNISHMENT_BY_ID",
  228. `Getting punishment with id ${punishmentId} failed. "${err}"`
  229. );
  230. return cb({ status: "error", message: err });
  231. }
  232. this.log("SUCCESS", "GET_PUNISHMENT_BY_ID", `Got punishment with id ${punishmentId} successful.`);
  233. return cb({ status: "success", data: { punishment } });
  234. });
  235. }),
  236. /**
  237. * Bans an IP address
  238. *
  239. * @param {object} session - the session object automatically added by the websocket
  240. * @param {string} value - the ip address that is going to be banned
  241. * @param {string} reason - the reason for the ban
  242. * @param {string} expiresAt - the time the ban expires
  243. * @param {Function} cb - gets called with the result
  244. */
  245. banIP: isAdminRequired(function banIP(session, value, reason, expiresAt, cb) {
  246. async.waterfall(
  247. [
  248. next => {
  249. if (!value) return next("You must provide an IP address to ban.");
  250. if (!reason) return next("You must provide a reason for the ban.");
  251. return next();
  252. },
  253. next => {
  254. if (!expiresAt || typeof expiresAt !== "string") return next("Invalid expire date.");
  255. const date = new Date();
  256. switch (expiresAt) {
  257. case "1h":
  258. expiresAt = date.setHours(date.getHours() + 1);
  259. break;
  260. case "12h":
  261. expiresAt = date.setHours(date.getHours() + 12);
  262. break;
  263. case "1d":
  264. expiresAt = date.setDate(date.getDate() + 1);
  265. break;
  266. case "1w":
  267. expiresAt = date.setDate(date.getDate() + 7);
  268. break;
  269. case "1m":
  270. expiresAt = date.setMonth(date.getMonth() + 1);
  271. break;
  272. case "3m":
  273. expiresAt = date.setMonth(date.getMonth() + 3);
  274. break;
  275. case "6m":
  276. expiresAt = date.setMonth(date.getMonth() + 6);
  277. break;
  278. case "1y":
  279. expiresAt = date.setFullYear(date.getFullYear() + 1);
  280. break;
  281. case "never":
  282. expiresAt = new Date(3093527980800000);
  283. break;
  284. default:
  285. return next("Invalid expire date.");
  286. }
  287. return next();
  288. },
  289. next => {
  290. PunishmentsModule.runJob(
  291. "ADD_PUNISHMENT",
  292. {
  293. type: "banUserIp",
  294. value,
  295. reason,
  296. expiresAt,
  297. punishedBy: session.userId
  298. },
  299. this
  300. )
  301. .then(punishment => {
  302. next(null, punishment);
  303. })
  304. .catch(next);
  305. }
  306. ],
  307. async (err, punishment) => {
  308. if (err && err !== true) {
  309. err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
  310. this.log(
  311. "ERROR",
  312. "BAN_IP",
  313. `User ${session.userId} failed to ban IP address ${value} with the reason ${reason}. '${err}'`
  314. );
  315. cb({ status: "error", message: err });
  316. }
  317. this.log(
  318. "SUCCESS",
  319. "BAN_IP",
  320. `User ${session.userId} has successfully banned IP address ${value} with the reason ${reason}.`
  321. );
  322. CacheModule.runJob("PUB", {
  323. channel: "ip.ban",
  324. value: { ip: value, punishment }
  325. });
  326. return cb({
  327. status: "success",
  328. message: "Successfully banned IP address."
  329. });
  330. }
  331. );
  332. })
  333. };