userAuth.ts 6.2 KB

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