fix: add credentials to all fetch calls for auth cookie support (#72)
* fix: add credentials to all fetch calls for auth cookie support - Add credentials: include to useMedications.ts fetch calls - Add credentials: include to MedicationsPage.tsx save function - Add credentials: include to useSettings.ts settings update - Add credentials: include to useShare.ts share generation - Add credentials: include to DashboardPage.tsx reminder email - Add credentials: include to PlannerPage.tsx usage calculation - Make create-release workflow skip if release already exists * fix: default to ntfy-style notifications for HTTP URLs - Change notification logic to use plain text format by default - Only use JSON format for known webhook services (Discord, Slack, Telegram, Gotify) - This fixes ntfy URLs not being recognized when hostname doesn't contain 'ntfy' * feat: highlight medication being edited - Add blue border and background to the medication row being edited - Show medication avatar and name in the edit form header - Makes it easy to identify which medication is being edited when there are many * fix: use proper URL parsing for webhook detection (CodeQL security fix) Replace vulnerable .includes() URL checks with proper URL hostname parsing to prevent bypass attacks (e.g., evil.com?hooks.slack.com). Fixes CodeQL alerts #33 and #34 (js/incomplete-url-substring-sanitization)
This commit is contained in:
@@ -22,7 +22,7 @@ export function useMedications(): UseMedicationsReturn {
|
||||
|
||||
const loadMeds = useCallback(() => {
|
||||
setLoading(true);
|
||||
fetch("/api/medications")
|
||||
fetch("/api/medications", { credentials: "include" })
|
||||
.then((res) => res.json())
|
||||
.then((data) => setMeds(Array.isArray(data) ? data : []))
|
||||
.catch(() => setMeds([]))
|
||||
@@ -31,7 +31,7 @@ export function useMedications(): UseMedicationsReturn {
|
||||
|
||||
const deleteMed = useCallback(
|
||||
async (id: number, editingId: number | null, resetForm: () => void) => {
|
||||
await fetch(`/api/medications/${id}`, { method: "DELETE" }).catch(() => null);
|
||||
await fetch(`/api/medications/${id}`, { method: "DELETE", credentials: "include" }).catch(() => null);
|
||||
if (editingId === id) resetForm();
|
||||
loadMeds();
|
||||
},
|
||||
@@ -48,6 +48,7 @@ export function useMedications(): UseMedicationsReturn {
|
||||
const res = await fetch(`/api/medications/${medId}/image`, {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
credentials: "include",
|
||||
});
|
||||
if (res.ok) {
|
||||
loadMeds();
|
||||
@@ -62,7 +63,7 @@ export function useMedications(): UseMedicationsReturn {
|
||||
|
||||
const deleteMedImage = useCallback(
|
||||
async (medId: number) => {
|
||||
await fetch(`/api/medications/${medId}/image`, { method: "DELETE" }).catch(() => null);
|
||||
await fetch(`/api/medications/${medId}/image`, { method: "DELETE", credentials: "include" }).catch(() => null);
|
||||
loadMeds();
|
||||
},
|
||||
[loadMeds]
|
||||
|
||||
@@ -210,6 +210,7 @@ export function useSettings(): UseSettingsReturn {
|
||||
await fetch("/api/settings", {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
body: JSON.stringify(payload),
|
||||
}).catch(() => null);
|
||||
|
||||
@@ -233,6 +234,7 @@ export function useSettings(): UseSettingsReturn {
|
||||
const res = await fetch("/api/settings/test-email", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
body: JSON.stringify({ email: settings.notificationEmail }),
|
||||
});
|
||||
const data = await res.json();
|
||||
@@ -254,6 +256,7 @@ export function useSettings(): UseSettingsReturn {
|
||||
const res = await fetch("/api/settings/test-shoutrrr", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
body: JSON.stringify({ url: settings.shoutrrrUrl }),
|
||||
});
|
||||
const data = await res.json();
|
||||
|
||||
@@ -59,6 +59,7 @@ export function useShare(): UseShareReturn {
|
||||
const res = await fetch("/api/share", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
takenBy: shareSelectedPerson,
|
||||
scheduleDays: shareSelectedDays,
|
||||
|
||||
Reference in New Issue
Block a user