user.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. const bcrypt = require('bcryptjs');
  2. const nanoid = require('nanoid');
  3. const subMinutes = require('date-fns/sub_minutes');
  4. const driver = require('./neo4j');
  5. exports.getUser = async ({ email = '', apikey = '' }) => {
  6. const session = driver.session();
  7. const { records = [] } = await session.readTransaction(tx =>
  8. tx.run(
  9. 'MATCH (u:USER) WHERE u.email = $email OR u.apikey = $apikey ' +
  10. 'OPTIONAL MATCH (u)-[r:RECEIVED]->(c) WITH u, collect(c.date) as cooldowns ' +
  11. 'OPTIONAL MATCH (u)-[:OWNS]->(d) RETURN u, d, cooldowns',
  12. {
  13. apikey,
  14. email,
  15. }
  16. )
  17. );
  18. session.close();
  19. const user = records.length && records[0].get('u').properties;
  20. const cooldowns = records.length && records[0].get('cooldowns');
  21. const domainProps = records.length && records[0].get('d');
  22. const domain = domainProps ? domainProps.properties.name : '';
  23. const homepage = domainProps ? domainProps.properties.homepage : '';
  24. const useHttps = domainProps ? domainProps.properties.useHttps : '';
  25. return user && { ...user, cooldowns, domain, homepage, useHttps };
  26. };
  27. exports.createUser = async ({ email, password }) => {
  28. const session = driver.session();
  29. const salt = await bcrypt.genSalt(12);
  30. const hash = await bcrypt.hash(password, salt);
  31. const verificationToken = nanoid(40);
  32. const { records = [] } = await session.writeTransaction(tx =>
  33. tx.run(
  34. 'MERGE (u:USER { email: $email }) ' +
  35. 'SET u.password = $hash , u.verified = $verified , ' +
  36. 'u.verificationToken = $verificationToken , u.createdAt = $createdAt ' +
  37. 'RETURN u',
  38. {
  39. email,
  40. hash,
  41. createdAt: new Date().toJSON(),
  42. verified: false,
  43. verificationToken,
  44. }
  45. )
  46. );
  47. session.close();
  48. const user = records[0].get('u').properties;
  49. return user;
  50. };
  51. exports.verifyUser = async ({ verificationToken }) => {
  52. const session = driver.session();
  53. const { records = [] } = await session.writeTransaction(tx =>
  54. tx.run(
  55. 'MATCH (u:USER { verificationToken: $verificationToken })' +
  56. 'SET u.verified = true SET u.verificationToken = NULL RETURN u',
  57. {
  58. verificationToken,
  59. }
  60. )
  61. );
  62. session.close();
  63. const user = records.length && records[0].get('u').properties;
  64. return user;
  65. };
  66. exports.changePassword = async ({ email, password }) => {
  67. const session = driver.session();
  68. const salt = await bcrypt.genSalt(12);
  69. const hash = await bcrypt.hash(password, salt);
  70. const { records = [] } = await session.writeTransaction(tx =>
  71. tx.run('MATCH (u:USER { email: $email }) SET u.password = $password RETURN u', {
  72. email,
  73. password: hash,
  74. })
  75. );
  76. session.close();
  77. const user = records.length && records[0].get('u').properties;
  78. return user;
  79. };
  80. exports.generateApiKey = async ({ email }) => {
  81. const session = driver.session();
  82. const apikey = nanoid(40);
  83. const { records = [] } = await session.writeTransaction(tx =>
  84. tx.run('MATCH (u:USER { email: $email }) SET u.apikey = $apikey RETURN u', {
  85. email,
  86. apikey,
  87. })
  88. );
  89. session.close();
  90. const newApikey = records.length && records[0].get('u').properties.apikey;
  91. return { apikey: newApikey };
  92. };
  93. exports.requestPasswordReset = async ({ email }) => {
  94. const session = driver.session();
  95. const resetPasswordExpires = Date.now() + 3600000;
  96. const resetPasswordToken = nanoid(40);
  97. const { records = [] } = await session.writeTransaction(tx =>
  98. tx.run(
  99. 'MATCH (u:USER { email: $email }) ' +
  100. 'SET u.resetPasswordToken = $resetPasswordToken ' +
  101. 'SET u.resetPasswordExpires = $resetPasswordExpires ' +
  102. 'RETURN u',
  103. {
  104. email,
  105. resetPasswordExpires,
  106. resetPasswordToken,
  107. }
  108. )
  109. );
  110. session.close();
  111. const user = records.length && records[0].get('u').properties;
  112. return user;
  113. };
  114. exports.resetPassword = async ({ resetPasswordToken }) => {
  115. const session = driver.session();
  116. const currentTime = Date.now();
  117. const { records = [] } = await session.writeTransaction(tx =>
  118. tx.run(
  119. 'MATCH (u:USER) ' +
  120. 'WHERE u.resetPasswordToken = $resetPasswordToken AND u.resetPasswordExpires > $currentTime ' +
  121. 'SET u.resetPasswordExpires = NULL, u.resetPasswordToken = NULL RETURN u',
  122. {
  123. resetPasswordToken,
  124. currentTime,
  125. }
  126. )
  127. );
  128. session.close();
  129. const user = records.length && records[0].get('u').properties;
  130. return user;
  131. };
  132. exports.addCooldown = async ({ email }) => {
  133. const session = driver.session();
  134. const { records = [] } = await session.writeTransaction(tx =>
  135. tx.run(
  136. 'MATCH (u:USER { email: $email }) ' +
  137. 'MERGE (u)-[r:RECEIVED]->(c:COOLDOWN { date: $date }) ' +
  138. 'RETURN COUNT(r) as count',
  139. {
  140. date: new Date().toJSON(),
  141. email,
  142. }
  143. )
  144. );
  145. session.close();
  146. const count = records.length && records[0].get('count').toNumber();
  147. return { count };
  148. };
  149. exports.getCooldowns = async ({ email }) => {
  150. const session = driver.session();
  151. const { records = [] } = await session.writeTransaction(tx =>
  152. tx.run('MATCH (u:USER { email: $email }) MATCH (u)-[r:RECEIVED]->(c) RETURN c.date as date', {
  153. date: new Date().toJSON(),
  154. email,
  155. })
  156. );
  157. session.close();
  158. const cooldowns = records.map(record => record.get('date'));
  159. return { cooldowns };
  160. };
  161. exports.banUser = async ({ email }) => {
  162. const session = driver.session();
  163. const { records = [] } = await session.writeTransaction(tx =>
  164. tx.run('MATCH (u:USER { email: $email }) SET u.banned = true RETURN u', {
  165. email,
  166. })
  167. );
  168. session.close();
  169. const user = records.length && records[0].get('u');
  170. return { user };
  171. };
  172. exports.addIPCooldown = async ip => {
  173. const session = driver.session();
  174. const { records = [] } = await session.writeTransaction(tx =>
  175. tx.run(
  176. 'MERGE (i:IP { ip: $ip }) ' +
  177. 'MERGE (i)-[r:RECEIVED]->(c:COOLDOWN { date: $date }) ' +
  178. 'RETURN COUNT(r) as count',
  179. {
  180. date: new Date().toJSON(),
  181. ip,
  182. }
  183. )
  184. );
  185. session.close();
  186. const count = records.length && records[0].get('count').toNumber();
  187. return count;
  188. };
  189. exports.getIPCooldown = async ip => {
  190. const session = driver.session();
  191. const { records = [] } = await session.readTransaction(tx =>
  192. tx.run(
  193. 'MATCH (i:IP { ip: $ip }) ' +
  194. 'MATCH (i)-[:RECEIVED]->(c:COOLDOWN) ' +
  195. 'WHERE c.date > $date ' +
  196. 'RETURN c.date as date',
  197. {
  198. date: subMinutes(new Date(), Number(process.env.NON_USER_COOLDOWN)).toJSON(),
  199. ip,
  200. }
  201. )
  202. );
  203. session.close();
  204. const count = records.length && records[0].get('date');
  205. return count;
  206. };
  207. exports.clearIPs = async () => {
  208. const session = driver.session();
  209. await session.writeTransaction(tx =>
  210. tx.run('MATCH (i:IP)-[:RECEIVED]->(c:COOLDOWN) WHERE c.date < $date DETACH DELETE i, c', {
  211. date: subMinutes(new Date(), Number(process.env.NON_USER_COOLDOWN)).toJSON(),
  212. })
  213. );
  214. session.close();
  215. };