userAuth.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. import { defineStore } from "pinia";
  2. import Toast from "toasters";
  3. import validation from "@/validation";
  4. import ws from "@/ws";
  5. export const useUserAuthStore = defineStore("userAuth", {
  6. state: () => ({
  7. userIdMap: {},
  8. userIdRequested: {},
  9. pendingUserIdCallbacks: {},
  10. loggedIn: false,
  11. role: "",
  12. username: "",
  13. email: "",
  14. userId: "",
  15. banned: false,
  16. ban: {
  17. reason: null,
  18. expiresAt: null
  19. },
  20. gotData: false
  21. }),
  22. actions: {
  23. register(user) {
  24. return new Promise((resolve, reject) => {
  25. const { username, email, password, recaptchaToken } = user;
  26. if (!email || !username || !password)
  27. reject(new Error("Please fill in all fields"));
  28. else if (!validation.isLength(email, 3, 254))
  29. reject(
  30. new Error(
  31. "Email must have between 3 and 254 characters."
  32. )
  33. );
  34. else if (
  35. email.indexOf("@") !== email.lastIndexOf("@") ||
  36. !validation.regex.emailSimple.test(email)
  37. )
  38. reject(new Error("Invalid email format."));
  39. else if (!validation.isLength(username, 2, 32))
  40. reject(
  41. new Error(
  42. "Username must have between 2 and 32 characters."
  43. )
  44. );
  45. else if (!validation.regex.azAZ09_.test(username))
  46. reject(
  47. new Error(
  48. "Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _."
  49. )
  50. );
  51. else if (username.replaceAll(/[_]/g, "").length === 0)
  52. reject(
  53. new Error(
  54. "Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _, and there has to be at least one letter or number."
  55. )
  56. );
  57. else if (!validation.isLength(password, 6, 200))
  58. reject(
  59. new Error(
  60. "Password must have between 6 and 200 characters."
  61. )
  62. );
  63. else if (!validation.regex.password.test(password))
  64. reject(
  65. new Error(
  66. "Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character."
  67. )
  68. );
  69. else
  70. ws.socket.dispatch(
  71. "users.register",
  72. username,
  73. email,
  74. password,
  75. recaptchaToken,
  76. res => {
  77. if (res.status === "success") {
  78. if (res.SID) {
  79. return lofig.get("cookie").then(cookie => {
  80. const date = new Date();
  81. date.setTime(
  82. new Date().getTime() +
  83. 2 * 365 * 24 * 60 * 60 * 1000
  84. );
  85. const secure = cookie.secure
  86. ? "secure=true; "
  87. : "";
  88. let domain = "";
  89. if (cookie.domain !== "localhost")
  90. domain = ` domain=${cookie.domain};`;
  91. document.cookie = `${cookie.SIDname}=${
  92. res.SID
  93. }; expires=${date.toUTCString()}; ${domain}${secure}path=/`;
  94. return resolve({
  95. status: "success",
  96. message: "Account registered!"
  97. });
  98. });
  99. }
  100. return reject(new Error("You must login"));
  101. }
  102. return reject(new Error(res.message));
  103. }
  104. );
  105. });
  106. },
  107. login(user) {
  108. return new Promise((resolve, reject) => {
  109. const { email, password } = user;
  110. ws.socket.dispatch("users.login", email, password, res => {
  111. if (res.status === "success") {
  112. return lofig.get("cookie").then(cookie => {
  113. const date = new Date();
  114. date.setTime(
  115. new Date().getTime() +
  116. 2 * 365 * 24 * 60 * 60 * 1000
  117. );
  118. const secure = cookie.secure ? "secure=true; " : "";
  119. let domain = "";
  120. if (cookie.domain !== "localhost")
  121. domain = ` domain=${cookie.domain};`;
  122. document.cookie = `${cookie.SIDname}=${
  123. res.data.SID
  124. }; expires=${date.toUTCString()}; ${domain}${secure}path=/`;
  125. const bc = new BroadcastChannel(
  126. `${cookie.SIDname}.user_login`
  127. );
  128. bc.postMessage(true);
  129. bc.close();
  130. return resolve({
  131. status: "success",
  132. message: "Logged in!"
  133. });
  134. });
  135. }
  136. return reject(new Error(res.message));
  137. });
  138. });
  139. },
  140. logout() {
  141. return new Promise((resolve, reject) => {
  142. ws.socket.dispatch("users.logout", res => {
  143. if (res.status === "success") {
  144. return resolve(
  145. lofig.get("cookie").then(cookie => {
  146. document.cookie = `${cookie.SIDname}=;expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
  147. return window.location.reload();
  148. })
  149. );
  150. }
  151. new Toast(res.message);
  152. return reject(new Error(res.message));
  153. });
  154. });
  155. },
  156. getBasicUser(userId) {
  157. return new Promise(resolve => {
  158. if (typeof this.userIdMap[`Z${userId}`] !== "string") {
  159. if (this.userIdRequested[`Z${userId}`] !== true) {
  160. this.requestingUserId(userId);
  161. ws.socket.dispatch(
  162. "users.getBasicUser",
  163. userId,
  164. res => {
  165. if (res.status === "success") {
  166. const user = res.data;
  167. this.mapUserId({
  168. userId,
  169. user: {
  170. name: user.name,
  171. username: user.username
  172. }
  173. });
  174. this.pendingUserIdCallbacks[
  175. `Z${userId}`
  176. ].forEach(cb => cb(user));
  177. this.clearPendingCallbacks(userId);
  178. return resolve(user);
  179. }
  180. return resolve(null);
  181. }
  182. );
  183. } else {
  184. this.pendingUser({
  185. userId,
  186. callback: user => resolve(user)
  187. });
  188. }
  189. } else {
  190. resolve(this.userIdMap[`Z${userId}`]);
  191. }
  192. });
  193. },
  194. mapUserId(data) {
  195. this.userIdMap[`Z${data.userId}`] = data.user;
  196. this.userIdRequested[`Z${data.userId}`] = false;
  197. },
  198. requestingUserId(userId) {
  199. this.userIdRequested[`Z${userId}`] = true;
  200. if (!this.pendingUserIdCallbacks[`Z${userId}`])
  201. this.pendingUserIdCallbacks[`Z${userId}`] = [];
  202. },
  203. pendingUser(data) {
  204. this.pendingUserIdCallbacks[`Z${data.userId}`].push(data.callback);
  205. },
  206. clearPendingCallbacks(userId) {
  207. this.pendingUserIdCallbacks[`Z${userId}`] = [];
  208. },
  209. authData(data) {
  210. this.loggedIn = data.loggedIn;
  211. this.role = data.role;
  212. this.username = data.username;
  213. this.email = data.email;
  214. this.userId = data.userId;
  215. this.gotData = true;
  216. },
  217. banUser(ban) {
  218. this.banned = true;
  219. this.ban = ban;
  220. },
  221. updateUsername(username) {
  222. this.username = username;
  223. }
  224. }
  225. });