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:
Ivan Bondarenko
2026-07-02 19:52:15 +02:00
committed by GitHub
parent 87468de8b6
commit 3ddb47ac02
9 changed files with 71 additions and 7 deletions

View File

@@ -8,6 +8,11 @@ import type { RecipeSearchQuery } from "~/lib/api/user/recipes/recipe";
export const allRecipes = ref<Recipe[]>([]);
export const recentRecipes = ref<Recipe[]>([]);
export function resetRecipes() {
allRecipes.value = [];
recentRecipes.value = [];
}
function getParams(
orderBy: string | null = null,
orderDirection = "desc",

View File

@@ -1,6 +1,7 @@
import { ref, computed } from "vue";
import type { UserOut } from "~/lib/api/types/user";
import { clearAllStores } from "~/composables/store";
import { clearComposableCaches } from "~/composables/use-clear-composable-caches";
import { getTokenCookieOptions } from "~/composables/use-token-cookie";
interface AuthData {
@@ -25,6 +26,11 @@ interface AuthState {
const authUser = ref<UserOut | null>(null);
const authStatus = ref<"loading" | "authenticated" | "unauthenticated">("loading");
export function resetAuth() {
authUser.value = null;
authStatus.value = "unauthenticated";
}
export const useAuthBackend = function (): AuthState {
const { $axios } = useNuxtApp();
const router = useRouter();
@@ -41,8 +47,7 @@ export const useAuthBackend = function (): AuthState {
// Only clear token on auth errors, not network errors
if (error?.response?.status === 401) {
setToken(null);
authUser.value = null;
authStatus.value = "unauthenticated";
resetAuth();
if (redirect) {
router.push("/login");
}
@@ -99,12 +104,14 @@ export const useAuthBackend = function (): AuthState {
}
finally {
setToken(null);
authUser.value = null;
authStatus.value = "unauthenticated";
resetAuth();
// Clear all cached store data to prevent data leakage between users
clearAllStores();
// Clear cached composable refs to prevent data leakage between users
clearComposableCaches();
// Clear Nuxt's useAsyncData cache
clearNuxtData();

View File

@@ -12,6 +12,13 @@ const backups = ref<AllBackups>({
templates: [],
});
export function resetBackups() {
backups.value = {
imports: [],
templates: [],
};
}
function setBackups(newBackups: AllBackups | null) {
if (newBackups) {
backups.value = newBackups;

View 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();
}

View File

@@ -7,6 +7,11 @@ import type { Recipe } from "~/lib/api/types/recipe";
const groupRecipeActions = ref<GroupRecipeActionOut[] | null>(null);
const loading = ref(false);
export function resetGroupRecipeActions() {
groupRecipeActions.value = null;
loading.value = false;
}
export function useGroupRecipeActionData() {
const data = reactive({
id: "",
@@ -85,9 +90,6 @@ export const useGroupRecipeActions = function (
loading,
{ orderBy: orderBy },
),
flushStore() {
groupRecipeActions.value = [];
},
};
return {

View File

@@ -4,6 +4,11 @@ import type { GroupBase, GroupInDB, GroupSummary } from "~/lib/api/types/user";
const groupSelfRef = ref<GroupSummary | null>(null);
const loading = ref(false);
export function resetGroupSelf() {
groupSelfRef.value = null;
loading.value = false;
}
export const useGroupSelf = function () {
const api = useUserApi();
const auth = useMealieAuth();

View File

@@ -4,6 +4,11 @@ import type { HouseholdCreate, HouseholdInDB } from "~/lib/api/types/household";
const householdSelfRef = ref<HouseholdInDB | null>(null);
const loading = ref(false);
export function resetHouseholdSelf() {
householdSelfRef.value = null;
loading.value = false;
}
export const useHouseholdSelf = function () {
const api = useUserApi();
const auth = useMealieAuth();

View File

@@ -5,6 +5,12 @@ const userRatings = ref<UserRatingSummary[]>([]);
const loading = ref(false);
const ready = ref(false);
export function resetUserSelfRatings() {
userRatings.value = [];
loading.value = false;
ready.value = false;
}
export const useUserSelfRatings = function () {
const auth = useMealieAuth();

View File

@@ -10,6 +10,16 @@ const password1 = ref("");
const password2 = ref("");
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 = () => {
const i18n = useI18n();