b491b6a146
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (push) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (push) Has been cancelled
Client Quality Gates / Shared client and Web (pull_request) Has been cancelled
Client Quality Gates / macOS Desktop (pull_request) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (pull_request) Has been cancelled
94 lines
2.9 KiB
TypeScript
94 lines
2.9 KiB
TypeScript
import { defineStore } from "pinia";
|
|
import { ref } from "vue";
|
|
import { getLoginKey, login as apiLogin, devLogin, fetchMe } from "../api/auth";
|
|
import { setToken, clearToken, getToken } from "../utils/auth";
|
|
import { encryptLoginPayload } from "../utils/loginCrypto";
|
|
import type { UserInfo } from "../types/api";
|
|
import { useStudyStore } from "./study";
|
|
import { useSessionStore } from "./session";
|
|
|
|
export const useAuthStore = defineStore("auth", () => {
|
|
const LAST_LOGIN_EMAIL_KEY = "ctms_last_login_email";
|
|
const allowInsecureDevLogin =
|
|
import.meta.env.VITE_RUNTIME_ENV === "development" &&
|
|
import.meta.env.VITE_ALLOW_INSECURE_DEV_LOGIN === "true";
|
|
const token = ref<string | null>(getToken());
|
|
const user = ref<UserInfo | null>(null);
|
|
const loading = ref(false);
|
|
const forceLogin = ref(false);
|
|
|
|
const login = async (email: string, password: string) => {
|
|
loading.value = true;
|
|
try {
|
|
const { data } =
|
|
allowInsecureDevLogin && !window.isSecureContext
|
|
? await devLogin({ email, password })
|
|
: await encryptedLogin(email, password);
|
|
token.value = data.access_token;
|
|
await setToken(data.access_token);
|
|
useSessionStore().resetActivity();
|
|
localStorage.setItem(LAST_LOGIN_EMAIL_KEY, email);
|
|
const me = await fetchMeAction();
|
|
const studyStore = useStudyStore();
|
|
const userKey = me?.email || email;
|
|
await studyStore.restoreStudyForUser(userKey, { preferActive: me?.is_admin });
|
|
await studyStore.loadCurrentStudyPermissions().catch(() => {});
|
|
forceLogin.value = false;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
const encryptedLogin = async (email: string, password: string) => {
|
|
const { data: loginKey } = await getLoginKey();
|
|
const ciphertext = await encryptLoginPayload(loginKey.public_key, {
|
|
email,
|
|
password,
|
|
challenge: loginKey.challenge,
|
|
});
|
|
return apiLogin({
|
|
key_id: loginKey.key_id,
|
|
challenge: loginKey.challenge,
|
|
ciphertext,
|
|
});
|
|
};
|
|
|
|
const fetchMeAction = async () => {
|
|
const { data } = await fetchMe();
|
|
user.value = data;
|
|
if (data?.email) {
|
|
localStorage.setItem(LAST_LOGIN_EMAIL_KEY, data.email);
|
|
}
|
|
return data;
|
|
};
|
|
|
|
const logout = async () => {
|
|
const studyStore = useStudyStore();
|
|
const sessionStore = useSessionStore();
|
|
const userKey = user.value?.email || localStorage.getItem(LAST_LOGIN_EMAIL_KEY) || "";
|
|
studyStore.rememberCurrentStudyForUser(userKey);
|
|
token.value = null;
|
|
user.value = null;
|
|
forceLogin.value = false;
|
|
sessionStore.resetActivity();
|
|
await clearToken();
|
|
studyStore.clearCurrentStudy();
|
|
};
|
|
|
|
return {
|
|
token,
|
|
user,
|
|
loading,
|
|
forceLogin,
|
|
login,
|
|
fetchMe: fetchMeAction,
|
|
logout,
|
|
setToken: (newToken: string) => {
|
|
token.value = newToken;
|
|
},
|
|
requestReLogin: () => {
|
|
forceLogin.value = true;
|
|
},
|
|
};
|
|
});
|