123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- import { defineStore } from "pinia";
- import Toast from "toasters";
- import validation from "@/validation";
- import { useWebsocketsStore } from "@/stores/websockets";
- import { useConfigStore } from "@/stores/config";
- export const useUserAuthStore = defineStore("userAuth", {
- state: (): {
- userIdMap: Record<string, { name: string; username: string }>;
- userIdRequested: Record<string, boolean>;
- pendingUserIdCallbacks: Record<
- string,
- ((basicUser: { name: string; username: string }) => void)[]
- >;
- loggedIn: boolean;
- role: "user" | "moderator" | "admin";
- username: string;
- email: string;
- userId: string;
- banned: boolean;
- ban: {
- reason: string;
- expiresAt: number;
- };
- gotData: boolean;
- gotPermissions: boolean;
- permissions: Record<string, boolean>;
- } => ({
- userIdMap: {},
- userIdRequested: {},
- pendingUserIdCallbacks: {},
- loggedIn: false,
- role: "",
- username: "",
- email: "",
- userId: "",
- banned: false,
- ban: {
- reason: null,
- expiresAt: null
- },
- gotData: false,
- gotPermissions: false,
- permissions: {}
- }),
- actions: {
- register(user: {
- username: string;
- email: string;
- password: string;
- recaptchaToken: string;
- }) {
- return new Promise((resolve, reject) => {
- const { username, email, password, recaptchaToken } = user;
- if (!email || !username || !password)
- reject(new Error("Please fill in all fields"));
- else if (!validation.isLength(email, 3, 254))
- reject(
- new Error(
- "Email must have between 3 and 254 characters."
- )
- );
- else if (
- email.indexOf("@") !== email.lastIndexOf("@") ||
- !validation.regex.emailSimple.test(email)
- )
- reject(new Error("Invalid email format."));
- else if (!validation.isLength(username, 2, 32))
- reject(
- new Error(
- "Username must have between 2 and 32 characters."
- )
- );
- else if (!validation.regex.azAZ09_.test(username))
- reject(
- new Error(
- "Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _."
- )
- );
- else if (username.replaceAll(/[_]/g, "").length === 0)
- reject(
- new Error(
- "Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _, and there has to be at least one letter or number."
- )
- );
- else if (!validation.isLength(password, 6, 200))
- reject(
- new Error(
- "Password must have between 6 and 200 characters."
- )
- );
- else if (!validation.regex.password.test(password))
- reject(
- new Error(
- "Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character."
- )
- );
- else {
- const { socket } = useWebsocketsStore();
- const configStore = useConfigStore();
- socket.dispatch(
- "users.register",
- username,
- email,
- password,
- recaptchaToken,
- res => {
- if (res.status === "success") {
- if (res.SID) {
- const date = new Date();
- date.setTime(
- new Date().getTime() +
- 2 * 365 * 24 * 60 * 60 * 1000
- );
- const secure = configStore.urls.secure
- ? "secure=true; "
- : "";
- let domain = "";
- if (configStore.urls.host !== "localhost")
- domain = ` domain=${configStore.urls.host};`;
- document.cookie = `${configStore.cookie}=${
- res.SID
- }; expires=${date.toUTCString()}; ${domain}${secure}path=/`;
- return resolve({
- status: "success",
- message: "Account registered!"
- });
- }
- return reject(new Error("You must login"));
- }
- return reject(new Error(res.message));
- }
- );
- }
- });
- },
- login(user: { email: string; password: string }) {
- return new Promise((resolve, reject) => {
- const { email, password } = user;
- const { socket } = useWebsocketsStore();
- const configStore = useConfigStore();
- socket.dispatch("users.login", email, password, res => {
- if (res.status === "success") {
- const date = new Date();
- date.setTime(
- new Date().getTime() + 2 * 365 * 24 * 60 * 60 * 1000
- );
- const secure = configStore.urls.secure
- ? "secure=true; "
- : "";
- let domain = "";
- if (configStore.urls.host !== "localhost")
- domain = ` domain=${configStore.urls.host};`;
- document.cookie = `${configStore.cookie}=${
- res.data.SID
- }; expires=${date.toUTCString()}; ${domain}${secure}path=/`;
- const bc = new BroadcastChannel(
- `${configStore.cookie}.user_login`
- );
- bc.postMessage(true);
- bc.close();
- return resolve({
- status: "success",
- message: "Logged in!"
- });
- }
- return reject(new Error(res.message));
- });
- });
- },
- logout() {
- return new Promise((resolve, reject) => {
- const { socket } = useWebsocketsStore();
- socket.dispatch("users.logout", res => {
- if (res.status === "success") {
- const configStore = useConfigStore();
- document.cookie = `${configStore.cookie}=;expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
- window.location.reload();
- return resolve(true);
- }
- new Toast(res.message);
- return reject(new Error(res.message));
- });
- });
- },
- getBasicUser(userId: string) {
- return new Promise(
- (
- resolve: (
- basicUser: { name: string; username: string } | null
- ) => void
- ) => {
- if (typeof this.userIdMap[`Z${userId}`] !== "string") {
- if (this.userIdRequested[`Z${userId}`] !== true) {
- this.requestingUserId(userId);
- const { socket } = useWebsocketsStore();
- socket.dispatch(
- "users.getBasicUser",
- userId,
- res => {
- if (res.status === "success") {
- const user = res.data;
- this.mapUserId({
- userId,
- user: {
- name: user.name,
- username: user.username
- }
- });
- this.pendingUserIdCallbacks[
- `Z${userId}`
- ].forEach(cb => cb(user));
- this.clearPendingCallbacks(userId);
- return resolve(user);
- }
- return resolve(null);
- }
- );
- } else {
- this.pendingUser(userId, user => resolve(user));
- }
- } else {
- resolve(this.userIdMap[`Z${userId}`]);
- }
- }
- );
- },
- mapUserId(data: {
- userId: string;
- user: { name: string; username: string };
- }) {
- this.userIdMap[`Z${data.userId}`] = data.user;
- this.userIdRequested[`Z${data.userId}`] = false;
- },
- requestingUserId(userId: string) {
- this.userIdRequested[`Z${userId}`] = true;
- if (!this.pendingUserIdCallbacks[`Z${userId}`])
- this.pendingUserIdCallbacks[`Z${userId}`] = [];
- },
- pendingUser(
- userId: string,
- callback: (basicUser: { name: string; username: string }) => void
- ) {
- this.pendingUserIdCallbacks[`Z${userId}`].push(callback);
- },
- clearPendingCallbacks(userId: string) {
- this.pendingUserIdCallbacks[`Z${userId}`] = [];
- },
- authData(data: {
- loggedIn: boolean;
- role: string;
- username: string;
- email: string;
- userId: string;
- }) {
- this.loggedIn = data.loggedIn;
- this.role = data.role;
- this.username = data.username;
- this.email = data.email;
- this.userId = data.userId;
- this.gotData = true;
- },
- banUser(ban: { reason: string; expiresAt: number }) {
- this.banned = true;
- this.ban = ban;
- },
- updateUsername(username: string) {
- this.username = username;
- },
- updateRole(role: string) {
- this.role = role;
- },
- hasPermission(permission: string) {
- return !!(this.permissions && this.permissions[permission]);
- },
- updatePermissions() {
- return new Promise(resolve => {
- const { socket } = useWebsocketsStore();
- socket.dispatch("utils.getPermissions", res => {
- this.permissions = res.data.permissions;
- this.gotPermissions = true;
- resolve(this.permissions);
- });
- });
- }
- }
- });
|