mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-07-10 17:50:20 -04:00
fix: clear cached recipe actions on logout to prevent cross-user leak (#7815)
Co-authored-by: Michael Genson <71845777+michael-genson@users.noreply.github.com> Co-authored-by: Michael Genson <genson.michael@gmail.com>
This commit is contained in:
@@ -8,6 +8,11 @@ import type { RecipeSearchQuery } from "~/lib/api/user/recipes/recipe";
|
|||||||
export const allRecipes = ref<Recipe[]>([]);
|
export const allRecipes = ref<Recipe[]>([]);
|
||||||
export const recentRecipes = ref<Recipe[]>([]);
|
export const recentRecipes = ref<Recipe[]>([]);
|
||||||
|
|
||||||
|
export function resetRecipes() {
|
||||||
|
allRecipes.value = [];
|
||||||
|
recentRecipes.value = [];
|
||||||
|
}
|
||||||
|
|
||||||
function getParams(
|
function getParams(
|
||||||
orderBy: string | null = null,
|
orderBy: string | null = null,
|
||||||
orderDirection = "desc",
|
orderDirection = "desc",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { ref, computed } from "vue";
|
import { ref, computed } from "vue";
|
||||||
import type { UserOut } from "~/lib/api/types/user";
|
import type { UserOut } from "~/lib/api/types/user";
|
||||||
import { clearAllStores } from "~/composables/store";
|
import { clearAllStores } from "~/composables/store";
|
||||||
|
import { clearComposableCaches } from "~/composables/use-clear-composable-caches";
|
||||||
import { getTokenCookieOptions } from "~/composables/use-token-cookie";
|
import { getTokenCookieOptions } from "~/composables/use-token-cookie";
|
||||||
|
|
||||||
interface AuthData {
|
interface AuthData {
|
||||||
@@ -25,6 +26,11 @@ interface AuthState {
|
|||||||
const authUser = ref<UserOut | null>(null);
|
const authUser = ref<UserOut | null>(null);
|
||||||
const authStatus = ref<"loading" | "authenticated" | "unauthenticated">("loading");
|
const authStatus = ref<"loading" | "authenticated" | "unauthenticated">("loading");
|
||||||
|
|
||||||
|
export function resetAuth() {
|
||||||
|
authUser.value = null;
|
||||||
|
authStatus.value = "unauthenticated";
|
||||||
|
}
|
||||||
|
|
||||||
export const useAuthBackend = function (): AuthState {
|
export const useAuthBackend = function (): AuthState {
|
||||||
const { $axios } = useNuxtApp();
|
const { $axios } = useNuxtApp();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -41,8 +47,7 @@ export const useAuthBackend = function (): AuthState {
|
|||||||
// Only clear token on auth errors, not network errors
|
// Only clear token on auth errors, not network errors
|
||||||
if (error?.response?.status === 401) {
|
if (error?.response?.status === 401) {
|
||||||
setToken(null);
|
setToken(null);
|
||||||
authUser.value = null;
|
resetAuth();
|
||||||
authStatus.value = "unauthenticated";
|
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
router.push("/login");
|
router.push("/login");
|
||||||
}
|
}
|
||||||
@@ -99,12 +104,14 @@ export const useAuthBackend = function (): AuthState {
|
|||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
setToken(null);
|
setToken(null);
|
||||||
authUser.value = null;
|
resetAuth();
|
||||||
authStatus.value = "unauthenticated";
|
|
||||||
|
|
||||||
// Clear all cached store data to prevent data leakage between users
|
// Clear all cached store data to prevent data leakage between users
|
||||||
clearAllStores();
|
clearAllStores();
|
||||||
|
|
||||||
|
// Clear cached composable refs to prevent data leakage between users
|
||||||
|
clearComposableCaches();
|
||||||
|
|
||||||
// Clear Nuxt's useAsyncData cache
|
// Clear Nuxt's useAsyncData cache
|
||||||
clearNuxtData();
|
clearNuxtData();
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ const backups = ref<AllBackups>({
|
|||||||
templates: [],
|
templates: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export function resetBackups() {
|
||||||
|
backups.value = {
|
||||||
|
imports: [],
|
||||||
|
templates: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function setBackups(newBackups: AllBackups | null) {
|
function setBackups(newBackups: AllBackups | null) {
|
||||||
if (newBackups) {
|
if (newBackups) {
|
||||||
backups.value = newBackups;
|
backups.value = newBackups;
|
||||||
|
|||||||
17
frontend/app/composables/use-clear-composable-caches.ts
Normal file
17
frontend/app/composables/use-clear-composable-caches.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { resetGroupRecipeActions } from "~/composables/use-group-recipe-actions";
|
||||||
|
import { resetGroupSelf } from "~/composables/use-groups";
|
||||||
|
import { resetHouseholdSelf } from "~/composables/use-households";
|
||||||
|
import { resetUserSelfRatings } from "~/composables/use-users/user-ratings";
|
||||||
|
import { resetBackups } from "~/composables/use-backups";
|
||||||
|
import { resetRecipes } from "~/composables/recipes/use-recipes";
|
||||||
|
import { resetUserRegistrationForm } from "~/composables/use-users/user-registration-form";
|
||||||
|
|
||||||
|
export function clearComposableCaches() {
|
||||||
|
resetGroupRecipeActions();
|
||||||
|
resetGroupSelf();
|
||||||
|
resetHouseholdSelf();
|
||||||
|
resetUserSelfRatings();
|
||||||
|
resetBackups();
|
||||||
|
resetRecipes();
|
||||||
|
resetUserRegistrationForm();
|
||||||
|
}
|
||||||
@@ -7,6 +7,11 @@ import type { Recipe } from "~/lib/api/types/recipe";
|
|||||||
const groupRecipeActions = ref<GroupRecipeActionOut[] | null>(null);
|
const groupRecipeActions = ref<GroupRecipeActionOut[] | null>(null);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
|
export function resetGroupRecipeActions() {
|
||||||
|
groupRecipeActions.value = null;
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
export function useGroupRecipeActionData() {
|
export function useGroupRecipeActionData() {
|
||||||
const data = reactive({
|
const data = reactive({
|
||||||
id: "",
|
id: "",
|
||||||
@@ -85,9 +90,6 @@ export const useGroupRecipeActions = function (
|
|||||||
loading,
|
loading,
|
||||||
{ orderBy: orderBy },
|
{ orderBy: orderBy },
|
||||||
),
|
),
|
||||||
flushStore() {
|
|
||||||
groupRecipeActions.value = [];
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ import type { GroupBase, GroupInDB, GroupSummary } from "~/lib/api/types/user";
|
|||||||
const groupSelfRef = ref<GroupSummary | null>(null);
|
const groupSelfRef = ref<GroupSummary | null>(null);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
|
export function resetGroupSelf() {
|
||||||
|
groupSelfRef.value = null;
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
export const useGroupSelf = function () {
|
export const useGroupSelf = function () {
|
||||||
const api = useUserApi();
|
const api = useUserApi();
|
||||||
const auth = useMealieAuth();
|
const auth = useMealieAuth();
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ import type { HouseholdCreate, HouseholdInDB } from "~/lib/api/types/household";
|
|||||||
const householdSelfRef = ref<HouseholdInDB | null>(null);
|
const householdSelfRef = ref<HouseholdInDB | null>(null);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
|
export function resetHouseholdSelf() {
|
||||||
|
householdSelfRef.value = null;
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
export const useHouseholdSelf = function () {
|
export const useHouseholdSelf = function () {
|
||||||
const api = useUserApi();
|
const api = useUserApi();
|
||||||
const auth = useMealieAuth();
|
const auth = useMealieAuth();
|
||||||
|
|||||||
@@ -5,6 +5,12 @@ const userRatings = ref<UserRatingSummary[]>([]);
|
|||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const ready = ref(false);
|
const ready = ref(false);
|
||||||
|
|
||||||
|
export function resetUserSelfRatings() {
|
||||||
|
userRatings.value = [];
|
||||||
|
loading.value = false;
|
||||||
|
ready.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
export const useUserSelfRatings = function () {
|
export const useUserSelfRatings = function () {
|
||||||
const auth = useMealieAuth();
|
const auth = useMealieAuth();
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,16 @@ const password1 = ref("");
|
|||||||
const password2 = ref("");
|
const password2 = ref("");
|
||||||
const advancedOptions = ref(false);
|
const advancedOptions = ref(false);
|
||||||
|
|
||||||
|
export function resetUserRegistrationForm() {
|
||||||
|
domAccountForm.value = null;
|
||||||
|
username.value = "";
|
||||||
|
fullName.value = "";
|
||||||
|
email.value = "";
|
||||||
|
password1.value = "";
|
||||||
|
password2.value = "";
|
||||||
|
advancedOptions.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
export const useUserRegistrationForm = () => {
|
export const useUserRegistrationForm = () => {
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user