user.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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 resetPasswordExprie = 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.resetPasswordExprie = $resetPasswordExprie ' +
  102. 'RETURN u',
  103. {
  104. email,
  105. resetPasswordExprie,
  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 { records = [] } = await session.writeTransaction(tx =>
  117. tx.run(
  118. 'MATCH (u:USER { resetPasswordToken: $resetPasswordToken })' +
  119. 'SET u.resetPasswordExprie = NULL SET u.resetPasswordToken = NULL RETURN u',
  120. {
  121. resetPasswordToken,
  122. }
  123. )
  124. );
  125. session.close();
  126. const user = records.length && records[0].get('u').properties;
  127. return user;
  128. };
  129. exports.addCooldown = async ({ email }) => {
  130. const session = driver.session();
  131. const { records = [] } = await session.writeTransaction(tx =>
  132. tx.run(
  133. 'MATCH (u:USER { email: $email }) ' +
  134. 'MERGE (u)-[r:RECEIVED]->(c:COOLDOWN { date: $date }) ' +
  135. 'RETURN COUNT(r) as count',
  136. {
  137. date: new Date().toJSON(),
  138. email,
  139. }
  140. )
  141. );
  142. session.close();
  143. const count = records.length && records[0].get('count').toNumber();
  144. return { count };
  145. };
  146. exports.getCooldowns = async ({ email }) => {
  147. const session = driver.session();
  148. const { records = [] } = await session.writeTransaction(tx =>
  149. tx.run('MATCH (u:USER { email: $email }) MATCH (u)-[r:RECEIVED]->(c) RETURN c.date as date', {
  150. date: new Date().toJSON(),
  151. email,
  152. })
  153. );
  154. session.close();
  155. const cooldowns = records.map(record => record.get('date'));
  156. return { cooldowns };
  157. };
  158. exports.banUser = async ({ email }) => {
  159. const session = driver.session();
  160. const { records = [] } = await session.writeTransaction(tx =>
  161. tx.run('MATCH (u:USER { email: $email }) SET u.banned = true RETURN u', {
  162. email,
  163. })
  164. );
  165. session.close();
  166. const user = records.length && records[0].get('u');
  167. return { user };
  168. };
  169. exports.addIPCooldown = async ip => {
  170. const session = driver.session();
  171. const { records = [] } = await session.writeTransaction(tx =>
  172. tx.run(
  173. 'MERGE (i:IP { ip: $ip }) ' +
  174. 'MERGE (i)-[r:RECEIVED]->(c:COOLDOWN { date: $date }) ' +
  175. 'RETURN COUNT(r) as count',
  176. {
  177. date: new Date().toJSON(),
  178. ip,
  179. }
  180. )
  181. );
  182. session.close();
  183. const count = records.length && records[0].get('count').toNumber();
  184. return count;
  185. };
  186. exports.getIPCooldown = async ip => {
  187. const session = driver.session();
  188. const { records = [] } = await session.readTransaction(tx =>
  189. tx.run(
  190. 'MATCH (i:IP { ip: $ip }) ' +
  191. 'MATCH (i)-[:RECEIVED]->(c:COOLDOWN) ' +
  192. 'WHERE c.date > $date ' +
  193. 'RETURN c.date as date',
  194. {
  195. date: subMinutes(new Date(), Number(process.env.NON_USER_COOLDOWN)).toJSON(),
  196. ip,
  197. }
  198. )
  199. );
  200. session.close();
  201. const count = records.length && records[0].get('date');
  202. return count;
  203. };
  204. exports.clearIPs = async () => {
  205. const session = driver.session();
  206. await session.writeTransaction(tx =>
  207. tx.run('MATCH (i:IP)-[:RECEIVED]->(c:COOLDOWN) WHERE c.date < $date DETACH DELETE i, c', {
  208. date: subMinutes(new Date(), Number(process.env.NON_USER_COOLDOWN)).toJSON(),
  209. })
  210. );
  211. session.close();
  212. };