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:
Daniel Volz
2026-01-25 19:10:41 +01:00
committed by GitHub
parent cab0fcbba7
commit d516bdea7d
9 changed files with 87 additions and 8 deletions
+1
View File
@@ -217,6 +217,7 @@ export function DashboardPage() {
const res = await fetch("/api/reminder/send-email", {
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
body: JSON.stringify({
email: settings.notificationEmail,
lowStock: coverage.low,
+16 -2
View File
@@ -192,6 +192,7 @@ export function MedicationsPage() {
method,
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
credentials: "include",
});
if (!res.ok) {
@@ -308,7 +309,7 @@ export function MedicationsPage() {
</div>
<div className="med-list">
{meds.map((med) => (
<div key={med.id} className="med-row">
<div key={med.id} className={`med-row${editingId === med.id ? " editing" : ""}`}>
<div className="med-header">
<div className="med-info">
<div className="med-name-row">
@@ -358,7 +359,20 @@ export function MedicationsPage() {
<article className="card form desktop-only">
<div className="card-head">
<h2>{editingId ? t("form.editEntry") : t("form.newEntry")}</h2>
{editingId ? (
<div className="edit-header">
<MedicationAvatar
name={meds.find((m) => m.id === editingId)?.name || ""}
imageUrl={meds.find((m) => m.id === editingId)?.imageUrl}
size="md"
/>
<h2>
{t("form.editEntry")}: {meds.find((m) => m.id === editingId)?.name}
</h2>
</div>
) : (
<h2>{t("form.newEntry")}</h2>
)}
</div>
<form className="form-grid" onSubmit={saveMedication}>
<label className={fieldErrors.name ? "has-error" : ""}>
+2
View File
@@ -82,6 +82,7 @@ export function PlannerPage() {
const rows = (await fetch("/api/medications/usage", {
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
body: JSON.stringify(body),
})
.then((res) => res.json())
@@ -113,6 +114,7 @@ export function PlannerPage() {
const res = await fetch("/api/planner/send-email", {
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
body: JSON.stringify({
email: settings.notificationEmail,
from: range.start,